blob: edcfce7becbc5ee25c0d0ecddba0a361ed3703c9 [file] [log] [blame]
Tom Rini70df9d62018-05-07 17:02:21 -04001// SPDX-License-Identifier: GPL-2.0+
Alexander Graf4aacacc2016-03-04 01:10:00 +01002/*
3 * EFI application console interface
4 *
5 * Copyright (c) 2016 Alexander Graf
Alexander Graf4aacacc2016-03-04 01:10:00 +01006 */
7
8#include <common.h>
Rob Clark0d138cf2017-09-09 06:47:40 -04009#include <charset.h>
Simon Glass9bc15642020-02-03 07:36:16 -070010#include <malloc.h>
Simon Glass495a5dc2019-11-14 12:57:30 -070011#include <time.h>
Rob Clark3863b712017-09-13 18:05:43 -040012#include <dm/device.h>
Alexander Graf4aacacc2016-03-04 01:10:00 +010013#include <efi_loader.h>
Simon Glass0af6e2d2019-08-01 09:46:52 -060014#include <env.h>
Rob Clark3863b712017-09-13 18:05:43 -040015#include <stdio_dev.h>
16#include <video_console.h>
Heinrich Schuchardte5c93172020-12-27 14:47:50 +010017#include <linux/delay.h>
Alexander Graf4aacacc2016-03-04 01:10:00 +010018
Emmanuel Vadota074d5d2016-11-08 06:03:29 +010019#define EFI_COUT_MODE_2 2
20#define EFI_MAX_COUT_MODE 3
21
22struct cout_mode {
23 unsigned long columns;
24 unsigned long rows;
25 int present;
26};
27
28static struct cout_mode efi_cout_modes[] = {
29 /* EFI Mode 0 is 80x25 and always present */
30 {
31 .columns = 80,
32 .rows = 25,
33 .present = 1,
34 },
35 /* EFI Mode 1 is always 80x50 */
36 {
37 .columns = 80,
38 .rows = 50,
39 .present = 0,
40 },
41 /* Value are unknown until we query the console */
42 {
43 .columns = 0,
44 .rows = 0,
45 .present = 0,
46 },
47};
48
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +020049const efi_guid_t efi_guid_text_input_ex_protocol =
50 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
Heinrich Schuchardt580c13b2017-10-26 19:25:59 +020051const efi_guid_t efi_guid_text_input_protocol =
52 EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID;
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +020053const efi_guid_t efi_guid_text_output_protocol =
54 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID;
Alexander Graf4aacacc2016-03-04 01:10:00 +010055
56#define cESC '\x1b'
57#define ESC "\x1b"
58
Emmanuel Vadota074d5d2016-11-08 06:03:29 +010059/* Default to mode 0 */
Alexander Graf4aacacc2016-03-04 01:10:00 +010060static struct simple_text_output_mode efi_con_mode = {
Emmanuel Vadota074d5d2016-11-08 06:03:29 +010061 .max_mode = 1,
Alexander Graf4aacacc2016-03-04 01:10:00 +010062 .mode = 0,
63 .attribute = 0,
64 .cursor_column = 0,
65 .cursor_row = 0,
66 .cursor_visible = 1,
67};
68
Matthias Brugger29c6f5f2019-03-05 12:50:18 +010069static int term_get_char(s32 *c)
70{
71 u64 timeout;
72
73 /* Wait up to 100 ms for a character */
74 timeout = timer_get_us() + 100000;
75
76 while (!tstc())
77 if (timer_get_us() > timeout)
78 return 1;
79
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +020080 *c = getchar();
Matthias Brugger29c6f5f2019-03-05 12:50:18 +010081 return 0;
82}
83
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +020084/**
Heinrich Schuchardt77135c22018-05-16 18:17:38 +020085 * Receive and parse a reply from the terminal.
86 *
87 * @n: array of return values
88 * @num: number of return values expected
89 * @end_char: character indicating end of terminal message
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +020090 * Return: non-zero indicates error
Heinrich Schuchardt77135c22018-05-16 18:17:38 +020091 */
92static int term_read_reply(int *n, int num, char end_char)
Alexander Graf4aacacc2016-03-04 01:10:00 +010093{
Matthias Brugger29c6f5f2019-03-05 12:50:18 +010094 s32 c;
Alexander Graf4aacacc2016-03-04 01:10:00 +010095 int i = 0;
96
Matthias Brugger29c6f5f2019-03-05 12:50:18 +010097 if (term_get_char(&c) || c != cESC)
Alexander Graf4aacacc2016-03-04 01:10:00 +010098 return -1;
Matthias Brugger29c6f5f2019-03-05 12:50:18 +010099
100 if (term_get_char(&c) || c != '[')
Alexander Graf4aacacc2016-03-04 01:10:00 +0100101 return -1;
102
103 n[0] = 0;
104 while (1) {
Matthias Brugger29c6f5f2019-03-05 12:50:18 +0100105 if (!term_get_char(&c)) {
106 if (c == ';') {
107 i++;
108 if (i >= num)
109 return -1;
110 n[i] = 0;
111 continue;
112 } else if (c == end_char) {
113 break;
114 } else if (c > '9' || c < '0') {
Alexander Graf4aacacc2016-03-04 01:10:00 +0100115 return -1;
Matthias Brugger29c6f5f2019-03-05 12:50:18 +0100116 }
117
118 /* Read one more decimal position */
119 n[i] *= 10;
120 n[i] += c - '0';
121 } else {
Alexander Graf4aacacc2016-03-04 01:10:00 +0100122 return -1;
123 }
Alexander Graf4aacacc2016-03-04 01:10:00 +0100124 }
Heinrich Schuchardt77135c22018-05-16 18:17:38 +0200125 if (i != num - 1)
126 return -1;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100127
128 return 0;
129}
130
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200131/**
132 * efi_cout_output_string() - write Unicode string to console
133 *
134 * This function implements the OutputString service of the simple text output
135 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
136 * for details.
137 *
138 * @this: simple text output protocol
139 * @string: u16 string
140 * Return: status code
141 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100142static efi_status_t EFIAPI efi_cout_output_string(
143 struct efi_simple_text_output_protocol *this,
Heinrich Schuchardt84494282021-01-05 07:50:09 +0100144 const u16 *string)
Alexander Graf4aacacc2016-03-04 01:10:00 +0100145{
Rob Clark1ef185d2017-09-13 18:05:44 -0400146 struct simple_text_output_mode *con = &efi_con_mode;
147 struct cout_mode *mode = &efi_cout_modes[con->mode];
Heinrich Schuchardta419d1d2018-08-31 21:31:32 +0200148 char *buf, *pos;
Heinrich Schuchardt84494282021-01-05 07:50:09 +0100149 const u16 *p;
Heinrich Schuchardta419d1d2018-08-31 21:31:32 +0200150 efi_status_t ret = EFI_SUCCESS;
Rob Clark1ef185d2017-09-13 18:05:44 -0400151
Heinrich Schuchardta419d1d2018-08-31 21:31:32 +0200152 EFI_ENTRY("%p, %p", this, string);
Rob Clark1ef185d2017-09-13 18:05:44 -0400153
Heinrich Schuchardte60b2982019-05-18 18:11:54 +0200154 if (!this || !string) {
155 ret = EFI_INVALID_PARAMETER;
156 goto out;
157 }
158
Heinrich Schuchardta419d1d2018-08-31 21:31:32 +0200159 buf = malloc(utf16_utf8_strlen(string) + 1);
160 if (!buf) {
161 ret = EFI_OUT_OF_RESOURCES;
162 goto out;
163 }
164 pos = buf;
165 utf16_utf8_strcpy(&pos, string);
Rob Clark1ef185d2017-09-13 18:05:44 -0400166 fputs(stdout, buf);
Heinrich Schuchardta419d1d2018-08-31 21:31:32 +0200167 free(buf);
Rob Clark1ef185d2017-09-13 18:05:44 -0400168
Heinrich Schuchardt8aaeed92018-04-29 16:24:25 +0200169 /*
170 * Update the cursor position.
171 *
172 * The UEFI spec provides advance rules for U+0000, U+0008, U+000A,
Heinrich Schuchardtda88da82019-09-04 21:13:45 +0200173 * and U000D. All other control characters are ignored. Any non-control
174 * character increase the column by one.
Heinrich Schuchardt8aaeed92018-04-29 16:24:25 +0200175 */
176 for (p = string; *p; ++p) {
Rob Clark1ef185d2017-09-13 18:05:44 -0400177 switch (*p) {
Heinrich Schuchardt8aaeed92018-04-29 16:24:25 +0200178 case '\b': /* U+0008, backspace */
Heinrich Schuchardtda88da82019-09-04 21:13:45 +0200179 if (con->cursor_column)
180 con->cursor_column--;
Rob Clark1ef185d2017-09-13 18:05:44 -0400181 break;
Heinrich Schuchardt8aaeed92018-04-29 16:24:25 +0200182 case '\n': /* U+000A, newline */
Rob Clark1ef185d2017-09-13 18:05:44 -0400183 con->cursor_column = 0;
184 con->cursor_row++;
185 break;
Heinrich Schuchardt8aaeed92018-04-29 16:24:25 +0200186 case '\r': /* U+000D, carriage-return */
187 con->cursor_column = 0;
Rob Clark1ef185d2017-09-13 18:05:44 -0400188 break;
Heinrich Schuchardt8aaeed92018-04-29 16:24:25 +0200189 case 0xd800 ... 0xdbff:
190 /*
191 * Ignore high surrogates, we do not want to count a
192 * Unicode character twice.
193 */
Rob Clark1ef185d2017-09-13 18:05:44 -0400194 break;
195 default:
Heinrich Schuchardtda88da82019-09-04 21:13:45 +0200196 /* Exclude control codes */
197 if (*p > 0x1f)
198 con->cursor_column++;
Rob Clark1ef185d2017-09-13 18:05:44 -0400199 break;
200 }
201 if (con->cursor_column >= mode->columns) {
202 con->cursor_column = 0;
203 con->cursor_row++;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100204 }
Heinrich Schuchardtda88da82019-09-04 21:13:45 +0200205 /*
206 * When we exceed the row count the terminal will scroll up one
207 * line. We have to adjust the cursor position.
208 */
209 if (con->cursor_row >= mode->rows && con->cursor_row)
210 con->cursor_row--;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100211 }
212
Heinrich Schuchardta419d1d2018-08-31 21:31:32 +0200213out:
214 return EFI_EXIT(ret);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100215}
216
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200217/**
218 * efi_cout_test_string() - test writing Unicode string to console
219 *
220 * This function implements the TestString service of the simple text output
221 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
222 * for details.
223 *
224 * As in OutputString we simply convert UTF-16 to UTF-8 there are no unsupported
225 * code points and we can always return EFI_SUCCESS.
226 *
227 * @this: simple text output protocol
228 * @string: u16 string
229 * Return: status code
230 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100231static efi_status_t EFIAPI efi_cout_test_string(
232 struct efi_simple_text_output_protocol *this,
Heinrich Schuchardt84494282021-01-05 07:50:09 +0100233 const u16 *string)
Alexander Graf4aacacc2016-03-04 01:10:00 +0100234{
235 EFI_ENTRY("%p, %p", this, string);
236 return EFI_EXIT(EFI_SUCCESS);
237}
238
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200239/**
240 * cout_mode_matches() - check if mode has given terminal size
241 *
242 * @mode: text mode
243 * @rows: number of rows
244 * @cols: number of columns
245 * Return: true if number of rows and columns matches the mode and
246 * the mode is present
247 */
Emmanuel Vadota074d5d2016-11-08 06:03:29 +0100248static bool cout_mode_matches(struct cout_mode *mode, int rows, int cols)
249{
250 if (!mode->present)
251 return false;
252
253 return (mode->rows == rows) && (mode->columns == cols);
254}
255
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200256/**
257 * query_console_serial() - query console size
258 *
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200259 * When using a serial console or the net console we can only devise the
260 * terminal size by querying the terminal using ECMA-48 control sequences.
261 *
Heinrich Schuchardtdc305ad2019-09-05 20:37:13 +0200262 * @rows: pointer to return number of rows
263 * @cols: pointer to return number of columns
264 * Returns: 0 on success
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200265 */
Rob Clark1e948922017-09-13 18:05:42 -0400266static int query_console_serial(int *rows, int *cols)
267{
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200268 int ret = 0;
269 int n[2];
Rob Clark1e948922017-09-13 18:05:42 -0400270
271 /* Empty input buffer */
272 while (tstc())
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200273 getchar();
Rob Clark1e948922017-09-13 18:05:42 -0400274
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200275 /*
276 * Not all terminals understand CSI [18t for querying the console size.
277 * We should adhere to escape sequences documented in the console_codes
Heinrich Schuchardt5e96f422018-10-18 21:51:38 +0200278 * man page and the ECMA-48 standard.
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200279 *
280 * So here we follow a different approach. We position the cursor to the
281 * bottom right and query its position. Before leaving the function we
282 * restore the original cursor position.
283 */
284 printf(ESC "7" /* Save cursor position */
285 ESC "[r" /* Set scrolling region to full window */
286 ESC "[999;999H" /* Move to bottom right corner */
287 ESC "[6n"); /* Query cursor position */
Rob Clark1e948922017-09-13 18:05:42 -0400288
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200289 /* Read {rows,cols} */
290 if (term_read_reply(n, 2, 'R')) {
291 ret = 1;
292 goto out;
293 }
Rob Clark1e948922017-09-13 18:05:42 -0400294
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200295 *cols = n[1];
296 *rows = n[0];
297out:
298 printf(ESC "8"); /* Restore cursor position */
299 return ret;
Rob Clark1e948922017-09-13 18:05:42 -0400300}
301
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200302/**
303 * query_console_size() - update the mode table.
Heinrich Schuchardt75b4e692018-04-29 20:02:46 +0200304 *
305 * By default the only mode available is 80x25. If the console has at least 50
306 * lines, enable mode 80x50. If we can query the console size and it is neither
307 * 80x25 nor 80x50, set it as an additional mode.
308 */
309static void query_console_size(void)
310{
311 const char *stdout_name = env_get("stdout");
Alexander Graf28795322018-06-03 15:51:17 +0200312 int rows = 25, cols = 80;
Heinrich Schuchardt75b4e692018-04-29 20:02:46 +0200313
314 if (stdout_name && !strcmp(stdout_name, "vidconsole") &&
315 IS_ENABLED(CONFIG_DM_VIDEO)) {
316 struct stdio_dev *stdout_dev =
317 stdio_get_by_name("vidconsole");
318 struct udevice *dev = stdout_dev->priv;
319 struct vidconsole_priv *priv =
320 dev_get_uclass_priv(dev);
321 rows = priv->rows;
322 cols = priv->cols;
323 } else if (query_console_serial(&rows, &cols)) {
324 return;
325 }
326
327 /* Test if we can have Mode 1 */
328 if (cols >= 80 && rows >= 50) {
329 efi_cout_modes[1].present = 1;
330 efi_con_mode.max_mode = 2;
331 }
332
333 /*
334 * Install our mode as mode 2 if it is different
335 * than mode 0 or 1 and set it as the currently selected mode
336 */
337 if (!cout_mode_matches(&efi_cout_modes[0], rows, cols) &&
338 !cout_mode_matches(&efi_cout_modes[1], rows, cols)) {
339 efi_cout_modes[EFI_COUT_MODE_2].columns = cols;
340 efi_cout_modes[EFI_COUT_MODE_2].rows = rows;
341 efi_cout_modes[EFI_COUT_MODE_2].present = 1;
342 efi_con_mode.max_mode = EFI_MAX_COUT_MODE;
343 efi_con_mode.mode = EFI_COUT_MODE_2;
344 }
345}
346
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200347
348/**
349 * efi_cout_query_mode() - get terminal size for a text mode
350 *
351 * This function implements the QueryMode service of the simple text output
352 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
353 * for details.
354 *
355 * @this: simple text output protocol
356 * @mode_number: mode number to retrieve information on
357 * @columns: number of columns
358 * @rows: number of rows
359 * Return: status code
360 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100361static efi_status_t EFIAPI efi_cout_query_mode(
362 struct efi_simple_text_output_protocol *this,
363 unsigned long mode_number, unsigned long *columns,
364 unsigned long *rows)
365{
366 EFI_ENTRY("%p, %ld, %p, %p", this, mode_number, columns, rows);
367
Emmanuel Vadota074d5d2016-11-08 06:03:29 +0100368 if (mode_number >= efi_con_mode.max_mode)
369 return EFI_EXIT(EFI_UNSUPPORTED);
370
371 if (efi_cout_modes[mode_number].present != 1)
372 return EFI_EXIT(EFI_UNSUPPORTED);
373
Alexander Graf4aacacc2016-03-04 01:10:00 +0100374 if (columns)
Emmanuel Vadota074d5d2016-11-08 06:03:29 +0100375 *columns = efi_cout_modes[mode_number].columns;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100376 if (rows)
Emmanuel Vadota074d5d2016-11-08 06:03:29 +0100377 *rows = efi_cout_modes[mode_number].rows;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100378
379 return EFI_EXIT(EFI_SUCCESS);
380}
381
Rob Clark87ef0012017-10-10 08:23:01 -0400382static const struct {
383 unsigned int fg;
384 unsigned int bg;
385} color[] = {
386 { 30, 40 }, /* 0: black */
387 { 34, 44 }, /* 1: blue */
388 { 32, 42 }, /* 2: green */
389 { 36, 46 }, /* 3: cyan */
390 { 31, 41 }, /* 4: red */
391 { 35, 45 }, /* 5: magenta */
Heinrich Schuchardt6e8eff22018-09-08 19:57:24 +0200392 { 33, 43 }, /* 6: brown, map to yellow as EDK2 does*/
393 { 37, 47 }, /* 7: light gray, map to white */
Rob Clark87ef0012017-10-10 08:23:01 -0400394};
395
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200396/**
397 * efi_cout_set_attribute() - set fore- and background color
398 *
399 * This function implements the SetAttribute service of the simple text output
400 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
401 * for details.
402 *
403 * @this: simple text output protocol
404 * @attribute: foreground color - bits 0-3, background color - bits 4-6
405 * Return: status code
406 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100407static efi_status_t EFIAPI efi_cout_set_attribute(
408 struct efi_simple_text_output_protocol *this,
409 unsigned long attribute)
410{
Rob Clark87ef0012017-10-10 08:23:01 -0400411 unsigned int bold = EFI_ATTR_BOLD(attribute);
412 unsigned int fg = EFI_ATTR_FG(attribute);
413 unsigned int bg = EFI_ATTR_BG(attribute);
414
Alexander Graf4aacacc2016-03-04 01:10:00 +0100415 EFI_ENTRY("%p, %lx", this, attribute);
416
Heinrich Schuchardt1e129622019-06-14 07:16:57 +0200417 efi_con_mode.attribute = attribute;
Rob Clark87ef0012017-10-10 08:23:01 -0400418 if (attribute)
419 printf(ESC"[%u;%u;%um", bold, color[fg].fg, color[bg].bg);
420 else
421 printf(ESC"[0;37;40m");
422
423 return EFI_EXIT(EFI_SUCCESS);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100424}
425
Heinrich Schuchardt7995cbe2019-12-22 07:15:55 +0000426/**
427 * efi_cout_clear_screen() - clear screen
428 *
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200429 * This function implements the ClearScreen service of the simple text output
430 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
431 * for details.
Heinrich Schuchardt7995cbe2019-12-22 07:15:55 +0000432 *
433 * @this: pointer to the protocol instance
434 * Return: status code
435 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100436static efi_status_t EFIAPI efi_cout_clear_screen(
437 struct efi_simple_text_output_protocol *this)
438{
439 EFI_ENTRY("%p", this);
440
Heinrich Schuchardt7995cbe2019-12-22 07:15:55 +0000441 /*
442 * The Linux console wants both a clear and a home command. The video
443 * uclass does not support <ESC>[H without coordinates, yet.
444 */
445 printf(ESC "[2J" ESC "[1;1H");
Heinrich Schuchardt2d099322018-07-05 08:18:00 +0200446 efi_con_mode.cursor_column = 0;
447 efi_con_mode.cursor_row = 0;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100448
449 return EFI_EXIT(EFI_SUCCESS);
450}
451
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200452/**
453 * efi_cout_clear_set_mode() - set text model
454 *
455 * This function implements the SetMode service of the simple text output
456 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
457 * for details.
458 *
459 * @this: pointer to the protocol instance
460 * @mode_number: number of the text mode to set
461 * Return: status code
462 */
Heinrich Schuchardt757cc4a2019-06-14 07:20:51 +0200463static efi_status_t EFIAPI efi_cout_set_mode(
464 struct efi_simple_text_output_protocol *this,
465 unsigned long mode_number)
466{
467 EFI_ENTRY("%p, %ld", this, mode_number);
468
469 if (mode_number >= efi_con_mode.max_mode)
470 return EFI_EXIT(EFI_UNSUPPORTED);
Heinrich Schuchardt6a6afa72019-09-04 22:46:13 +0200471
472 if (!efi_cout_modes[mode_number].present)
473 return EFI_EXIT(EFI_UNSUPPORTED);
474
Heinrich Schuchardt757cc4a2019-06-14 07:20:51 +0200475 efi_con_mode.mode = mode_number;
476 EFI_CALL(efi_cout_clear_screen(this));
477
478 return EFI_EXIT(EFI_SUCCESS);
479}
480
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200481/**
482 * efi_cout_reset() - reset the terminal
483 *
484 * This function implements the Reset service of the simple text output
485 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
486 * for details.
487 *
488 * @this: pointer to the protocol instance
489 * @extended_verification: if set an extended verification may be executed
490 * Return: status code
491 */
Heinrich Schuchardt09866c22018-07-05 19:58:07 +0200492static efi_status_t EFIAPI efi_cout_reset(
493 struct efi_simple_text_output_protocol *this,
494 char extended_verification)
495{
496 EFI_ENTRY("%p, %d", this, extended_verification);
497
498 /* Clear screen */
499 EFI_CALL(efi_cout_clear_screen(this));
500 /* Set default colors */
Heinrich Schuchardt1e129622019-06-14 07:16:57 +0200501 efi_con_mode.attribute = 0x07;
Heinrich Schuchardt09866c22018-07-05 19:58:07 +0200502 printf(ESC "[0;37;40m");
503
504 return EFI_EXIT(EFI_SUCCESS);
505}
506
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200507/**
508 * efi_cout_set_cursor_position() - reset the terminal
509 *
510 * This function implements the SetCursorPosition service of the simple text
511 * output protocol. See the Unified Extensible Firmware Interface (UEFI)
512 * specification for details.
513 *
514 * @this: pointer to the protocol instance
515 * @column: column to move to
516 * @row: row to move to
517 * Return: status code
518 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100519static efi_status_t EFIAPI efi_cout_set_cursor_position(
520 struct efi_simple_text_output_protocol *this,
521 unsigned long column, unsigned long row)
522{
Heinrich Schuchardtdcac1d92018-09-14 18:49:26 +0200523 efi_status_t ret = EFI_SUCCESS;
524 struct simple_text_output_mode *con = &efi_con_mode;
525 struct cout_mode *mode = &efi_cout_modes[con->mode];
526
Alexander Graf4aacacc2016-03-04 01:10:00 +0100527 EFI_ENTRY("%p, %ld, %ld", this, column, row);
528
Heinrich Schuchardtdcac1d92018-09-14 18:49:26 +0200529 /* Check parameters */
530 if (!this) {
531 ret = EFI_INVALID_PARAMETER;
532 goto out;
533 }
534 if (row >= mode->rows || column >= mode->columns) {
535 ret = EFI_UNSUPPORTED;
536 goto out;
537 }
538
539 /*
540 * Set cursor position by sending CSI H.
541 * EFI origin is [0, 0], terminal origin is [1, 1].
542 */
543 printf(ESC "[%d;%dH", (int)row + 1, (int)column + 1);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100544 efi_con_mode.cursor_column = column;
545 efi_con_mode.cursor_row = row;
Heinrich Schuchardtdcac1d92018-09-14 18:49:26 +0200546out:
547 return EFI_EXIT(ret);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100548}
549
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200550/**
551 * efi_cout_enable_cursor() - enable the cursor
552 *
553 * This function implements the EnableCursor service of the simple text output
554 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
555 * for details.
556 *
557 * @this: pointer to the protocol instance
558 * @enable: if true enable, if false disable the cursor
559 * Return: status code
560 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100561static efi_status_t EFIAPI efi_cout_enable_cursor(
562 struct efi_simple_text_output_protocol *this,
563 bool enable)
564{
565 EFI_ENTRY("%p, %d", this, enable);
566
567 printf(ESC"[?25%c", enable ? 'h' : 'l');
Heinrich Schuchardt53f26b92019-06-02 22:54:28 +0200568 efi_con_mode.cursor_visible = !!enable;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100569
570 return EFI_EXIT(EFI_SUCCESS);
571}
572
Heinrich Schuchardt580c13b2017-10-26 19:25:59 +0200573struct efi_simple_text_output_protocol efi_con_out = {
Alexander Graf4aacacc2016-03-04 01:10:00 +0100574 .reset = efi_cout_reset,
575 .output_string = efi_cout_output_string,
576 .test_string = efi_cout_test_string,
577 .query_mode = efi_cout_query_mode,
578 .set_mode = efi_cout_set_mode,
579 .set_attribute = efi_cout_set_attribute,
580 .clear_screen = efi_cout_clear_screen,
581 .set_cursor_position = efi_cout_set_cursor_position,
582 .enable_cursor = efi_cout_enable_cursor,
583 .mode = (void*)&efi_con_mode,
584};
585
Heinrich Schuchardt695691e2018-09-11 22:38:12 +0200586/**
587 * struct efi_cin_notify_function - registered console input notify function
588 *
589 * @link: link to list
Heinrich Schuchardtdc305ad2019-09-05 20:37:13 +0200590 * @key: key to notify
Heinrich Schuchardt695691e2018-09-11 22:38:12 +0200591 * @function: function to call
592 */
593struct efi_cin_notify_function {
594 struct list_head link;
595 struct efi_key_data key;
596 efi_status_t (EFIAPI *function)
597 (struct efi_key_data *key_data);
598};
599
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200600static bool key_available;
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200601static struct efi_key_data next_key;
Heinrich Schuchardt695691e2018-09-11 22:38:12 +0200602static LIST_HEAD(cin_notify_functions);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100603
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200604/**
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200605 * set_shift_mask() - set shift mask
606 *
607 * @mod: Xterm shift mask
Heinrich Schuchardtdc305ad2019-09-05 20:37:13 +0200608 * @key_state: receives the state of the shift, alt, control, and logo keys
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200609 */
610void set_shift_mask(int mod, struct efi_key_state *key_state)
611{
612 key_state->key_shift_state = EFI_SHIFT_STATE_VALID;
613 if (mod) {
614 --mod;
615 if (mod & 1)
616 key_state->key_shift_state |= EFI_LEFT_SHIFT_PRESSED;
617 if (mod & 2)
618 key_state->key_shift_state |= EFI_LEFT_ALT_PRESSED;
619 if (mod & 4)
620 key_state->key_shift_state |= EFI_LEFT_CONTROL_PRESSED;
Heinrich Schuchardtfea93d62019-06-16 22:33:20 +0200621 if (!mod || (mod & 8))
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200622 key_state->key_shift_state |= EFI_LEFT_LOGO_PRESSED;
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200623 }
624}
625
626/**
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200627 * analyze_modifiers() - analyze modifiers (shift, alt, ctrl) for function keys
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200628 *
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100629 * This gets called when we have already parsed CSI.
630 *
Heinrich Schuchardtdc305ad2019-09-05 20:37:13 +0200631 * @key_state: receives the state of the shift, alt, control, and logo keys
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200632 * Return: the unmodified code
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100633 */
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200634static int analyze_modifiers(struct efi_key_state *key_state)
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100635{
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200636 int c, mod = 0, ret = 0;
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100637
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200638 c = getchar();
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100639
640 if (c != ';') {
641 ret = c;
642 if (c == '~')
643 goto out;
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200644 c = getchar();
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100645 }
646 for (;;) {
647 switch (c) {
648 case '0'...'9':
649 mod *= 10;
650 mod += c - '0';
651 /* fall through */
652 case ';':
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200653 c = getchar();
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100654 break;
655 default:
656 goto out;
657 }
658 }
659out:
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200660 set_shift_mask(mod, key_state);
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100661 if (!ret)
662 ret = c;
663 return ret;
664}
665
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200666/**
667 * efi_cin_read_key() - read a key from the console input
668 *
669 * @key: - key received
670 * Return: - status code
671 */
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200672static efi_status_t efi_cin_read_key(struct efi_key_data *key)
Alexander Graf4aacacc2016-03-04 01:10:00 +0100673{
674 struct efi_input_key pressed_key = {
675 .scan_code = 0,
676 .unicode_char = 0,
677 };
Heinrich Schuchardtfc5f1a12018-09-12 00:05:32 +0200678 s32 ch;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100679
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200680 if (console_read_unicode(&ch))
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200681 return EFI_NOT_READY;
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200682
683 key->key_state.key_shift_state = EFI_SHIFT_STATE_INVALID;
684 key->key_state.key_toggle_state = EFI_TOGGLE_STATE_INVALID;
685
Heinrich Schuchardtfc5f1a12018-09-12 00:05:32 +0200686 /* We do not support multi-word codes */
687 if (ch >= 0x10000)
688 ch = '?';
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200689
690 switch (ch) {
691 case 0x1b:
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100692 /*
Heinrich Schuchardte5c93172020-12-27 14:47:50 +0100693 * If a second key is received within 10 ms, assume that we are
694 * dealing with an escape sequence. Otherwise consider this the
695 * escape key being hit. 10 ms is long enough to work fine at
696 * 1200 baud and above.
697 */
698 udelay(10000);
699 if (!tstc()) {
700 pressed_key.scan_code = 23;
701 break;
702 }
703 /*
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100704 * Xterm Control Sequences
705 * https://www.xfree86.org/4.8.0/ctlseqs.html
706 */
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200707 ch = getchar();
Alexander Graf4aacacc2016-03-04 01:10:00 +0100708 switch (ch) {
709 case cESC: /* ESC */
710 pressed_key.scan_code = 23;
711 break;
Heinrich Schuchardt46e41d02019-06-16 21:41:13 +0200712 case 'O': /* F1 - F4, End */
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200713 ch = getchar();
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200714 /* consider modifiers */
Heinrich Schuchardt46e41d02019-06-16 21:41:13 +0200715 if (ch == 'F') { /* End */
716 pressed_key.scan_code = 6;
717 break;
718 } else if (ch < 'P') {
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200719 set_shift_mask(ch - '0', &key->key_state);
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200720 ch = getchar();
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200721 }
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100722 pressed_key.scan_code = ch - 'P' + 11;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100723 break;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100724 case '[':
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200725 ch = getchar();
Alexander Graf4aacacc2016-03-04 01:10:00 +0100726 switch (ch) {
727 case 'A'...'D': /* up, down right, left */
728 pressed_key.scan_code = ch - 'A' + 1;
729 break;
730 case 'F': /* End */
731 pressed_key.scan_code = 6;
732 break;
733 case 'H': /* Home */
734 pressed_key.scan_code = 5;
735 break;
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100736 case '1':
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200737 ch = analyze_modifiers(&key->key_state);
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100738 switch (ch) {
739 case '1'...'5': /* F1 - F5 */
740 pressed_key.scan_code = ch - '1' + 11;
741 break;
Heinrich Schuchardt46e41d02019-06-16 21:41:13 +0200742 case '6'...'9': /* F5 - F8 */
743 pressed_key.scan_code = ch - '6' + 15;
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100744 break;
745 case 'A'...'D': /* up, down right, left */
746 pressed_key.scan_code = ch - 'A' + 1;
747 break;
Heinrich Schuchardt46e41d02019-06-16 21:41:13 +0200748 case 'F': /* End */
749 pressed_key.scan_code = 6;
750 break;
751 case 'H': /* Home */
752 pressed_key.scan_code = 5;
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100753 break;
Heinrich Schuchardt46e41d02019-06-16 21:41:13 +0200754 case '~': /* Home */
755 pressed_key.scan_code = 5;
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100756 break;
757 }
Alexander Graf4aacacc2016-03-04 01:10:00 +0100758 break;
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100759 case '2':
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200760 ch = analyze_modifiers(&key->key_state);
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100761 switch (ch) {
762 case '0'...'1': /* F9 - F10 */
763 pressed_key.scan_code = ch - '0' + 19;
764 break;
765 case '3'...'4': /* F11 - F12 */
766 pressed_key.scan_code = ch - '3' + 21;
767 break;
768 case '~': /* INS */
769 pressed_key.scan_code = 7;
770 break;
771 }
Alexander Graf4aacacc2016-03-04 01:10:00 +0100772 break;
773 case '3': /* DEL */
774 pressed_key.scan_code = 8;
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200775 analyze_modifiers(&key->key_state);
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100776 break;
777 case '5': /* PG UP */
778 pressed_key.scan_code = 9;
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200779 analyze_modifiers(&key->key_state);
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100780 break;
781 case '6': /* PG DOWN */
782 pressed_key.scan_code = 10;
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200783 analyze_modifiers(&key->key_state);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100784 break;
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200785 } /* [ */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100786 break;
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200787 default:
788 /* ALT key */
789 set_shift_mask(3, &key->key_state);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100790 }
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200791 break;
792 case 0x7f:
Alexander Graf4aacacc2016-03-04 01:10:00 +0100793 /* Backspace */
794 ch = 0x08;
795 }
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200796 if (pressed_key.scan_code) {
797 key->key_state.key_shift_state |= EFI_SHIFT_STATE_VALID;
798 } else {
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100799 pressed_key.unicode_char = ch;
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200800
801 /*
802 * Assume left control key for control characters typically
803 * entered using the control key.
804 */
805 if (ch >= 0x01 && ch <= 0x1f) {
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200806 key->key_state.key_shift_state |=
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200807 EFI_SHIFT_STATE_VALID;
808 switch (ch) {
809 case 0x01 ... 0x07:
810 case 0x0b ... 0x0c:
811 case 0x0e ... 0x1f:
812 key->key_state.key_shift_state |=
813 EFI_LEFT_CONTROL_PRESSED;
814 }
815 }
816 }
817 key->key = pressed_key;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100818
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200819 return EFI_SUCCESS;
820}
821
822/**
Heinrich Schuchardt695691e2018-09-11 22:38:12 +0200823 * efi_cin_notify() - notify registered functions
824 */
825static void efi_cin_notify(void)
826{
827 struct efi_cin_notify_function *item;
828
829 list_for_each_entry(item, &cin_notify_functions, link) {
830 bool match = true;
831
832 /* We do not support toggle states */
833 if (item->key.key.unicode_char || item->key.key.scan_code) {
834 if (item->key.key.unicode_char !=
835 next_key.key.unicode_char ||
836 item->key.key.scan_code != next_key.key.scan_code)
837 match = false;
838 }
839 if (item->key.key_state.key_shift_state &&
840 item->key.key_state.key_shift_state !=
841 next_key.key_state.key_shift_state)
842 match = false;
843
844 if (match)
845 /* We don't bother about the return code */
846 EFI_CALL(item->function(&next_key));
847 }
848}
849
850/**
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200851 * efi_cin_check() - check if keyboard input is available
852 */
853static void efi_cin_check(void)
854{
855 efi_status_t ret;
856
857 if (key_available) {
Heinrich Schuchardt7b4b8d862019-06-07 06:47:01 +0200858 efi_signal_event(efi_con_in.wait_for_key);
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200859 return;
860 }
861
862 if (tstc()) {
863 ret = efi_cin_read_key(&next_key);
864 if (ret == EFI_SUCCESS) {
865 key_available = true;
866
Heinrich Schuchardt695691e2018-09-11 22:38:12 +0200867 /* Notify registered functions */
868 efi_cin_notify();
869
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200870 /* Queue the wait for key event */
Heinrich Schuchardt695691e2018-09-11 22:38:12 +0200871 if (key_available)
Heinrich Schuchardt7b4b8d862019-06-07 06:47:01 +0200872 efi_signal_event(efi_con_in.wait_for_key);
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200873 }
874 }
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200875}
876
877/**
878 * efi_cin_empty_buffer() - empty input buffer
879 */
880static void efi_cin_empty_buffer(void)
881{
882 while (tstc())
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200883 getchar();
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200884 key_available = false;
885}
886
887/**
888 * efi_cin_reset_ex() - reset console input
889 *
890 * @this: - the extended simple text input protocol
891 * @extended_verification: - extended verification
892 *
893 * This function implements the reset service of the
894 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
895 *
896 * See the Unified Extensible Firmware Interface (UEFI) specification for
897 * details.
898 *
899 * Return: old value of the task priority level
900 */
901static efi_status_t EFIAPI efi_cin_reset_ex(
902 struct efi_simple_text_input_ex_protocol *this,
903 bool extended_verification)
904{
905 efi_status_t ret = EFI_SUCCESS;
906
907 EFI_ENTRY("%p, %d", this, extended_verification);
908
909 /* Check parameters */
910 if (!this) {
911 ret = EFI_INVALID_PARAMETER;
912 goto out;
913 }
914
915 efi_cin_empty_buffer();
916out:
917 return EFI_EXIT(ret);
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200918}
919
920/**
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200921 * efi_cin_read_key_stroke_ex() - read key stroke
922 *
923 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
924 * @key_data: key read from console
925 * Return: status code
926 *
927 * This function implements the ReadKeyStrokeEx service of the
928 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
929 *
930 * See the Unified Extensible Firmware Interface (UEFI) specification for
931 * details.
932 */
933static efi_status_t EFIAPI efi_cin_read_key_stroke_ex(
934 struct efi_simple_text_input_ex_protocol *this,
935 struct efi_key_data *key_data)
936{
937 efi_status_t ret = EFI_SUCCESS;
938
939 EFI_ENTRY("%p, %p", this, key_data);
940
941 /* Check parameters */
942 if (!this || !key_data) {
943 ret = EFI_INVALID_PARAMETER;
944 goto out;
945 }
946
947 /* We don't do interrupts, so check for timers cooperatively */
948 efi_timer_check();
949
950 /* Enable console input after ExitBootServices */
951 efi_cin_check();
952
953 if (!key_available) {
954 ret = EFI_NOT_READY;
955 goto out;
956 }
Heinrich Schuchardt00b00a12019-04-06 20:59:24 +0200957 /*
958 * CTRL+A - CTRL+Z have to be signaled as a - z.
959 * SHIFT+CTRL+A - SHIFT+CTRL+Z have to be signaled as A - Z.
960 */
961 switch (next_key.key.unicode_char) {
962 case 0x01 ... 0x07:
963 case 0x0b ... 0x0c:
964 case 0x0e ... 0x1a:
965 if (!(next_key.key_state.key_toggle_state &
966 EFI_CAPS_LOCK_ACTIVE) ^
967 !(next_key.key_state.key_shift_state &
968 (EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED)))
969 next_key.key.unicode_char += 0x40;
970 else
971 next_key.key.unicode_char += 0x60;
972 }
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200973 *key_data = next_key;
974 key_available = false;
975 efi_con_in.wait_for_key->is_signaled = false;
Heinrich Schuchardt00b00a12019-04-06 20:59:24 +0200976
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200977out:
978 return EFI_EXIT(ret);
979}
980
981/**
982 * efi_cin_set_state() - set toggle key state
983 *
984 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
Heinrich Schuchardta41ccf92019-05-18 17:07:52 +0200985 * @key_toggle_state: pointer to key toggle state
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200986 * Return: status code
987 *
988 * This function implements the SetState service of the
989 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
990 *
991 * See the Unified Extensible Firmware Interface (UEFI) specification for
992 * details.
993 */
994static efi_status_t EFIAPI efi_cin_set_state(
995 struct efi_simple_text_input_ex_protocol *this,
Heinrich Schuchardta41ccf92019-05-18 17:07:52 +0200996 u8 *key_toggle_state)
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200997{
Heinrich Schuchardta41ccf92019-05-18 17:07:52 +0200998 EFI_ENTRY("%p, %p", this, key_toggle_state);
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200999 /*
1000 * U-Boot supports multiple console input sources like serial and
1001 * net console for which a key toggle state cannot be set at all.
1002 *
1003 * According to the UEFI specification it is allowable to not implement
1004 * this service.
1005 */
1006 return EFI_EXIT(EFI_UNSUPPORTED);
1007}
1008
1009/**
1010 * efi_cin_register_key_notify() - register key notification function
1011 *
1012 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
1013 * @key_data: key to be notified
1014 * @key_notify_function: function to be called if the key is pressed
1015 * @notify_handle: handle for unregistering the notification
1016 * Return: status code
1017 *
1018 * This function implements the SetState service of the
1019 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
1020 *
1021 * See the Unified Extensible Firmware Interface (UEFI) specification for
1022 * details.
1023 */
1024static efi_status_t EFIAPI efi_cin_register_key_notify(
1025 struct efi_simple_text_input_ex_protocol *this,
1026 struct efi_key_data *key_data,
1027 efi_status_t (EFIAPI *key_notify_function)(
1028 struct efi_key_data *key_data),
1029 void **notify_handle)
1030{
Heinrich Schuchardt695691e2018-09-11 22:38:12 +02001031 efi_status_t ret = EFI_SUCCESS;
1032 struct efi_cin_notify_function *notify_function;
1033
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001034 EFI_ENTRY("%p, %p, %p, %p",
1035 this, key_data, key_notify_function, notify_handle);
Heinrich Schuchardt695691e2018-09-11 22:38:12 +02001036
1037 /* Check parameters */
1038 if (!this || !key_data || !key_notify_function || !notify_handle) {
1039 ret = EFI_INVALID_PARAMETER;
1040 goto out;
1041 }
1042
1043 EFI_PRINT("u+%04x, sc %04x, sh %08x, tg %02x\n",
1044 key_data->key.unicode_char,
1045 key_data->key.scan_code,
1046 key_data->key_state.key_shift_state,
1047 key_data->key_state.key_toggle_state);
1048
1049 notify_function = calloc(1, sizeof(struct efi_cin_notify_function));
1050 if (!notify_function) {
1051 ret = EFI_OUT_OF_RESOURCES;
1052 goto out;
1053 }
1054 notify_function->key = *key_data;
1055 notify_function->function = key_notify_function;
1056 list_add_tail(&notify_function->link, &cin_notify_functions);
1057 *notify_handle = notify_function;
1058out:
1059 return EFI_EXIT(ret);
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001060}
1061
1062/**
1063 * efi_cin_unregister_key_notify() - unregister key notification function
1064 *
1065 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
1066 * @notification_handle: handle received when registering
1067 * Return: status code
1068 *
1069 * This function implements the SetState service of the
1070 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
1071 *
1072 * See the Unified Extensible Firmware Interface (UEFI) specification for
1073 * details.
1074 */
1075static efi_status_t EFIAPI efi_cin_unregister_key_notify(
1076 struct efi_simple_text_input_ex_protocol *this,
1077 void *notification_handle)
1078{
Heinrich Schuchardt695691e2018-09-11 22:38:12 +02001079 efi_status_t ret = EFI_INVALID_PARAMETER;
1080 struct efi_cin_notify_function *item, *notify_function =
1081 notification_handle;
1082
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001083 EFI_ENTRY("%p, %p", this, notification_handle);
Heinrich Schuchardt695691e2018-09-11 22:38:12 +02001084
1085 /* Check parameters */
1086 if (!this || !notification_handle)
1087 goto out;
1088
1089 list_for_each_entry(item, &cin_notify_functions, link) {
1090 if (item == notify_function) {
1091 ret = EFI_SUCCESS;
1092 break;
1093 }
1094 }
1095 if (ret != EFI_SUCCESS)
1096 goto out;
1097
1098 /* Remove the notify function */
1099 list_del(&notify_function->link);
1100 free(notify_function);
1101out:
1102 return EFI_EXIT(ret);
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001103}
1104
1105
1106/**
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001107 * efi_cin_reset() - drain the input buffer
1108 *
1109 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
1110 * @extended_verification: allow for exhaustive verification
1111 * Return: status code
1112 *
1113 * This function implements the Reset service of the
1114 * EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
1115 *
1116 * See the Unified Extensible Firmware Interface (UEFI) specification for
1117 * details.
1118 */
1119static efi_status_t EFIAPI efi_cin_reset
1120 (struct efi_simple_text_input_protocol *this,
1121 bool extended_verification)
1122{
1123 efi_status_t ret = EFI_SUCCESS;
1124
1125 EFI_ENTRY("%p, %d", this, extended_verification);
1126
1127 /* Check parameters */
1128 if (!this) {
1129 ret = EFI_INVALID_PARAMETER;
1130 goto out;
1131 }
1132
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001133 efi_cin_empty_buffer();
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001134out:
1135 return EFI_EXIT(ret);
1136}
1137
1138/**
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001139 * efi_cin_read_key_stroke() - read key stroke
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001140 *
1141 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
1142 * @key: key read from console
1143 * Return: status code
1144 *
1145 * This function implements the ReadKeyStroke service of the
1146 * EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
1147 *
1148 * See the Unified Extensible Firmware Interface (UEFI) specification for
1149 * details.
1150 */
1151static efi_status_t EFIAPI efi_cin_read_key_stroke
1152 (struct efi_simple_text_input_protocol *this,
1153 struct efi_input_key *key)
1154{
1155 efi_status_t ret = EFI_SUCCESS;
1156
1157 EFI_ENTRY("%p, %p", this, key);
1158
1159 /* Check parameters */
1160 if (!this || !key) {
1161 ret = EFI_INVALID_PARAMETER;
1162 goto out;
1163 }
1164
1165 /* We don't do interrupts, so check for timers cooperatively */
1166 efi_timer_check();
1167
1168 /* Enable console input after ExitBootServices */
1169 efi_cin_check();
1170
1171 if (!key_available) {
1172 ret = EFI_NOT_READY;
1173 goto out;
1174 }
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001175 *key = next_key.key;
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001176 key_available = false;
1177 efi_con_in.wait_for_key->is_signaled = false;
1178out:
1179 return EFI_EXIT(ret);
Alexander Graf4aacacc2016-03-04 01:10:00 +01001180}
1181
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001182static struct efi_simple_text_input_ex_protocol efi_con_in_ex = {
1183 .reset = efi_cin_reset_ex,
1184 .read_key_stroke_ex = efi_cin_read_key_stroke_ex,
1185 .wait_for_key_ex = NULL,
1186 .set_state = efi_cin_set_state,
1187 .register_key_notify = efi_cin_register_key_notify,
1188 .unregister_key_notify = efi_cin_unregister_key_notify,
1189};
1190
Heinrich Schuchardt3dabffd2018-09-08 10:20:10 +02001191struct efi_simple_text_input_protocol efi_con_in = {
Alexander Graf4aacacc2016-03-04 01:10:00 +01001192 .reset = efi_cin_reset,
1193 .read_key_stroke = efi_cin_read_key_stroke,
1194 .wait_for_key = NULL,
1195};
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001196
1197static struct efi_event *console_timer_event;
1198
Heinrich Schuchardtd8b878a2018-01-19 20:24:51 +01001199/*
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001200 * efi_console_timer_notify() - notify the console timer event
Heinrich Schuchardtd8b878a2018-01-19 20:24:51 +01001201 *
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001202 * @event: console timer event
1203 * @context: not used
Heinrich Schuchardtd8b878a2018-01-19 20:24:51 +01001204 */
xypron.glpk@gmx.de0ce42dc2017-07-20 05:26:07 +02001205static void EFIAPI efi_console_timer_notify(struct efi_event *event,
1206 void *context)
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001207{
1208 EFI_ENTRY("%p, %p", event, context);
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001209 efi_cin_check();
1210 EFI_EXIT(EFI_SUCCESS);
1211}
Heinrich Schuchardtd8b878a2018-01-19 20:24:51 +01001212
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001213/**
1214 * efi_key_notify() - notify the wait for key event
1215 *
1216 * @event: wait for key event
1217 * @context: not used
1218 */
1219static void EFIAPI efi_key_notify(struct efi_event *event, void *context)
1220{
1221 EFI_ENTRY("%p, %p", event, context);
1222 efi_cin_check();
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001223 EFI_EXIT(EFI_SUCCESS);
1224}
1225
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001226/**
1227 * efi_console_register() - install the console protocols
1228 *
1229 * This function is called from do_bootefi_exec().
Heinrich Schuchardta92e9ab2018-10-02 06:08:26 +02001230 *
1231 * Return: status code
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001232 */
Heinrich Schuchardta92e9ab2018-10-02 06:08:26 +02001233efi_status_t efi_console_register(void)
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001234{
1235 efi_status_t r;
Heinrich Schuchardtadb50d02018-09-26 05:27:55 +02001236 efi_handle_t console_output_handle;
1237 efi_handle_t console_input_handle;
Rob Clark49f7b4b2017-07-24 10:39:01 -04001238
Heinrich Schuchardt75b4e692018-04-29 20:02:46 +02001239 /* Set up mode information */
1240 query_console_size();
1241
Heinrich Schuchardt580c13b2017-10-26 19:25:59 +02001242 /* Create handles */
Heinrich Schuchardtadb50d02018-09-26 05:27:55 +02001243 r = efi_create_handle(&console_output_handle);
Heinrich Schuchardt580c13b2017-10-26 19:25:59 +02001244 if (r != EFI_SUCCESS)
1245 goto out_of_memory;
Alexander Graf36bab912018-09-04 14:59:11 +02001246
Heinrich Schuchardtadb50d02018-09-26 05:27:55 +02001247 r = efi_add_protocol(console_output_handle,
Heinrich Schuchardt580c13b2017-10-26 19:25:59 +02001248 &efi_guid_text_output_protocol, &efi_con_out);
1249 if (r != EFI_SUCCESS)
1250 goto out_of_memory;
Heinrich Schuchardtadb50d02018-09-26 05:27:55 +02001251 systab.con_out_handle = console_output_handle;
1252 systab.stderr_handle = console_output_handle;
Alexander Graf36bab912018-09-04 14:59:11 +02001253
Heinrich Schuchardtadb50d02018-09-26 05:27:55 +02001254 r = efi_create_handle(&console_input_handle);
Heinrich Schuchardt580c13b2017-10-26 19:25:59 +02001255 if (r != EFI_SUCCESS)
1256 goto out_of_memory;
Alexander Graf36bab912018-09-04 14:59:11 +02001257
Heinrich Schuchardtadb50d02018-09-26 05:27:55 +02001258 r = efi_add_protocol(console_input_handle,
Heinrich Schuchardt580c13b2017-10-26 19:25:59 +02001259 &efi_guid_text_input_protocol, &efi_con_in);
1260 if (r != EFI_SUCCESS)
1261 goto out_of_memory;
Heinrich Schuchardtadb50d02018-09-26 05:27:55 +02001262 systab.con_in_handle = console_input_handle;
1263 r = efi_add_protocol(console_input_handle,
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001264 &efi_guid_text_input_ex_protocol, &efi_con_in_ex);
1265 if (r != EFI_SUCCESS)
1266 goto out_of_memory;
Rob Clark49f7b4b2017-07-24 10:39:01 -04001267
Heinrich Schuchardt580c13b2017-10-26 19:25:59 +02001268 /* Create console events */
Heinrich Schuchardtbf7f1692018-02-18 15:17:52 +01001269 r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK, efi_key_notify,
1270 NULL, NULL, &efi_con_in.wait_for_key);
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001271 if (r != EFI_SUCCESS) {
1272 printf("ERROR: Failed to register WaitForKey event\n");
1273 return r;
1274 }
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001275 efi_con_in_ex.wait_for_key_ex = efi_con_in.wait_for_key;
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001276 r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
Heinrich Schuchardtbf7f1692018-02-18 15:17:52 +01001277 efi_console_timer_notify, NULL, NULL,
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001278 &console_timer_event);
1279 if (r != EFI_SUCCESS) {
1280 printf("ERROR: Failed to register console event\n");
1281 return r;
1282 }
1283 /* 5000 ns cycle is sufficient for 2 MBaud */
1284 r = efi_set_timer(console_timer_event, EFI_TIMER_PERIODIC, 50);
1285 if (r != EFI_SUCCESS)
1286 printf("ERROR: Failed to set console timer\n");
1287 return r;
Heinrich Schuchardt580c13b2017-10-26 19:25:59 +02001288out_of_memory:
Heinrich Schuchardt6e8eff22018-09-08 19:57:24 +02001289 printf("ERROR: Out of memory\n");
Heinrich Schuchardt580c13b2017-10-26 19:25:59 +02001290 return r;
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001291}