blob: e310f2f53ae1cd4bf6f558d3128956677ec8075e [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
Heinrich Schuchardt761908e2022-06-14 08:02:03 +02008#define LOG_CATEGORY LOGC_EFI
9
Masahisa Kojimac5ff0a02022-09-12 17:33:50 +090010#include <ansi.h>
Rob Clark0d138cf2017-09-09 06:47:40 -040011#include <charset.h>
Simon Glass9bc15642020-02-03 07:36:16 -070012#include <malloc.h>
Simon Glass495a5dc2019-11-14 12:57:30 -070013#include <time.h>
Rob Clark3863b712017-09-13 18:05:43 -040014#include <dm/device.h>
Alexander Graf4aacacc2016-03-04 01:10:00 +010015#include <efi_loader.h>
Simon Glass0af6e2d2019-08-01 09:46:52 -060016#include <env.h>
Heinrich Schuchardt761908e2022-06-14 08:02:03 +020017#include <log.h>
Rob Clark3863b712017-09-13 18:05:43 -040018#include <stdio_dev.h>
19#include <video_console.h>
Heinrich Schuchardte5c93172020-12-27 14:47:50 +010020#include <linux/delay.h>
Alexander Graf4aacacc2016-03-04 01:10:00 +010021
Emmanuel Vadota074d5d2016-11-08 06:03:29 +010022#define EFI_COUT_MODE_2 2
23#define EFI_MAX_COUT_MODE 3
24
25struct cout_mode {
26 unsigned long columns;
27 unsigned long rows;
28 int present;
29};
30
Heinrich Schuchardt81244ea2022-02-04 20:47:09 +010031__maybe_unused static struct efi_object uart_obj;
32
Simon Glassab312512025-05-10 14:54:38 +020033/*
34 * suppress emission of ANSI escape-characters for use by unit tests. Leave it
35 * as 0 for the default behaviour
36 */
37static bool no_ansi;
38
39void efi_console_set_ansi(bool allow_ansi)
40{
41 no_ansi = !allow_ansi;
42}
43
Emmanuel Vadota074d5d2016-11-08 06:03:29 +010044static struct cout_mode efi_cout_modes[] = {
45 /* EFI Mode 0 is 80x25 and always present */
46 {
47 .columns = 80,
48 .rows = 25,
49 .present = 1,
50 },
51 /* EFI Mode 1 is always 80x50 */
52 {
53 .columns = 80,
54 .rows = 50,
55 .present = 0,
56 },
57 /* Value are unknown until we query the console */
58 {
59 .columns = 0,
60 .rows = 0,
61 .present = 0,
62 },
63};
64
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +020065const efi_guid_t efi_guid_text_input_ex_protocol =
66 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
Heinrich Schuchardt580c13b2017-10-26 19:25:59 +020067const efi_guid_t efi_guid_text_input_protocol =
68 EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID;
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +020069const efi_guid_t efi_guid_text_output_protocol =
70 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID;
Alexander Graf4aacacc2016-03-04 01:10:00 +010071
72#define cESC '\x1b'
73#define ESC "\x1b"
74
Heinrich Schuchardt761908e2022-06-14 08:02:03 +020075/*
76 * efi_con_mode - mode information of the Simple Text Output Protocol
77 *
78 * Use safe settings before efi_setup_console_size() is called.
79 * By default enable only the 80x25 mode which must always exist.
80 */
Alexander Graf4aacacc2016-03-04 01:10:00 +010081static struct simple_text_output_mode efi_con_mode = {
Emmanuel Vadota074d5d2016-11-08 06:03:29 +010082 .max_mode = 1,
Alexander Graf4aacacc2016-03-04 01:10:00 +010083 .mode = 0,
84 .attribute = 0,
85 .cursor_column = 0,
86 .cursor_row = 0,
87 .cursor_visible = 1,
88};
89
Heinrich Schuchardtef6c69e2023-03-03 22:04:26 +010090/**
91 * term_get_char() - read a character from the console
92 *
93 * Wait for up to 100 ms to read a character from the console.
94 *
95 * @c: pointer to the buffer to receive the character
96 * Return: 0 on success, 1 otherwise
97 */
Matthias Brugger29c6f5f2019-03-05 12:50:18 +010098static int term_get_char(s32 *c)
99{
100 u64 timeout;
101
102 /* Wait up to 100 ms for a character */
103 timeout = timer_get_us() + 100000;
104
105 while (!tstc())
106 if (timer_get_us() > timeout)
107 return 1;
108
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200109 *c = getchar();
Matthias Brugger29c6f5f2019-03-05 12:50:18 +0100110 return 0;
111}
112
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200113/**
Heinrich Schuchardtb0102502024-09-18 23:37:28 +0200114 * term_read_reply() - receive and parse a reply from the terminal
Heinrich Schuchardt77135c22018-05-16 18:17:38 +0200115 *
116 * @n: array of return values
117 * @num: number of return values expected
118 * @end_char: character indicating end of terminal message
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200119 * Return: non-zero indicates error
Heinrich Schuchardt77135c22018-05-16 18:17:38 +0200120 */
121static int term_read_reply(int *n, int num, char end_char)
Alexander Graf4aacacc2016-03-04 01:10:00 +0100122{
Matthias Brugger29c6f5f2019-03-05 12:50:18 +0100123 s32 c;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100124 int i = 0;
125
Matthias Brugger29c6f5f2019-03-05 12:50:18 +0100126 if (term_get_char(&c) || c != cESC)
Alexander Graf4aacacc2016-03-04 01:10:00 +0100127 return -1;
Matthias Brugger29c6f5f2019-03-05 12:50:18 +0100128
129 if (term_get_char(&c) || c != '[')
Alexander Graf4aacacc2016-03-04 01:10:00 +0100130 return -1;
131
132 n[0] = 0;
133 while (1) {
Matthias Brugger29c6f5f2019-03-05 12:50:18 +0100134 if (!term_get_char(&c)) {
135 if (c == ';') {
136 i++;
137 if (i >= num)
138 return -1;
139 n[i] = 0;
140 continue;
141 } else if (c == end_char) {
142 break;
143 } else if (c > '9' || c < '0') {
Alexander Graf4aacacc2016-03-04 01:10:00 +0100144 return -1;
Matthias Brugger29c6f5f2019-03-05 12:50:18 +0100145 }
146
147 /* Read one more decimal position */
148 n[i] *= 10;
149 n[i] += c - '0';
150 } else {
Alexander Graf4aacacc2016-03-04 01:10:00 +0100151 return -1;
152 }
Alexander Graf4aacacc2016-03-04 01:10:00 +0100153 }
Heinrich Schuchardt77135c22018-05-16 18:17:38 +0200154 if (i != num - 1)
155 return -1;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100156
157 return 0;
158}
159
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200160/**
161 * efi_cout_output_string() - write Unicode string to console
162 *
163 * This function implements the OutputString service of the simple text output
164 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
165 * for details.
166 *
167 * @this: simple text output protocol
168 * @string: u16 string
169 * Return: status code
170 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100171static efi_status_t EFIAPI efi_cout_output_string(
172 struct efi_simple_text_output_protocol *this,
Heinrich Schuchardt84494282021-01-05 07:50:09 +0100173 const u16 *string)
Alexander Graf4aacacc2016-03-04 01:10:00 +0100174{
Rob Clark1ef185d2017-09-13 18:05:44 -0400175 struct simple_text_output_mode *con = &efi_con_mode;
176 struct cout_mode *mode = &efi_cout_modes[con->mode];
Heinrich Schuchardta419d1d2018-08-31 21:31:32 +0200177 char *buf, *pos;
Heinrich Schuchardt84494282021-01-05 07:50:09 +0100178 const u16 *p;
Heinrich Schuchardta419d1d2018-08-31 21:31:32 +0200179 efi_status_t ret = EFI_SUCCESS;
Rob Clark1ef185d2017-09-13 18:05:44 -0400180
Heinrich Schuchardta419d1d2018-08-31 21:31:32 +0200181 EFI_ENTRY("%p, %p", this, string);
Rob Clark1ef185d2017-09-13 18:05:44 -0400182
Heinrich Schuchardte60b2982019-05-18 18:11:54 +0200183 if (!this || !string) {
184 ret = EFI_INVALID_PARAMETER;
185 goto out;
186 }
187
Heinrich Schuchardta419d1d2018-08-31 21:31:32 +0200188 buf = malloc(utf16_utf8_strlen(string) + 1);
189 if (!buf) {
190 ret = EFI_OUT_OF_RESOURCES;
191 goto out;
192 }
193 pos = buf;
194 utf16_utf8_strcpy(&pos, string);
Simon Glass380c843a2024-09-01 19:18:12 -0600195 puts(buf);
Heinrich Schuchardta419d1d2018-08-31 21:31:32 +0200196 free(buf);
Rob Clark1ef185d2017-09-13 18:05:44 -0400197
Heinrich Schuchardt8aaeed92018-04-29 16:24:25 +0200198 /*
199 * Update the cursor position.
200 *
201 * The UEFI spec provides advance rules for U+0000, U+0008, U+000A,
Heinrich Schuchardtda88da82019-09-04 21:13:45 +0200202 * and U000D. All other control characters are ignored. Any non-control
203 * character increase the column by one.
Heinrich Schuchardt8aaeed92018-04-29 16:24:25 +0200204 */
205 for (p = string; *p; ++p) {
Rob Clark1ef185d2017-09-13 18:05:44 -0400206 switch (*p) {
Heinrich Schuchardt8aaeed92018-04-29 16:24:25 +0200207 case '\b': /* U+0008, backspace */
Heinrich Schuchardtda88da82019-09-04 21:13:45 +0200208 if (con->cursor_column)
209 con->cursor_column--;
Rob Clark1ef185d2017-09-13 18:05:44 -0400210 break;
Heinrich Schuchardt8aaeed92018-04-29 16:24:25 +0200211 case '\n': /* U+000A, newline */
Rob Clark1ef185d2017-09-13 18:05:44 -0400212 con->cursor_column = 0;
213 con->cursor_row++;
214 break;
Heinrich Schuchardt8aaeed92018-04-29 16:24:25 +0200215 case '\r': /* U+000D, carriage-return */
216 con->cursor_column = 0;
Rob Clark1ef185d2017-09-13 18:05:44 -0400217 break;
Heinrich Schuchardt8aaeed92018-04-29 16:24:25 +0200218 case 0xd800 ... 0xdbff:
219 /*
220 * Ignore high surrogates, we do not want to count a
221 * Unicode character twice.
222 */
Rob Clark1ef185d2017-09-13 18:05:44 -0400223 break;
224 default:
Heinrich Schuchardtda88da82019-09-04 21:13:45 +0200225 /* Exclude control codes */
226 if (*p > 0x1f)
227 con->cursor_column++;
Rob Clark1ef185d2017-09-13 18:05:44 -0400228 break;
229 }
230 if (con->cursor_column >= mode->columns) {
231 con->cursor_column = 0;
232 con->cursor_row++;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100233 }
Heinrich Schuchardtda88da82019-09-04 21:13:45 +0200234 /*
235 * When we exceed the row count the terminal will scroll up one
236 * line. We have to adjust the cursor position.
237 */
238 if (con->cursor_row >= mode->rows && con->cursor_row)
239 con->cursor_row--;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100240 }
241
Heinrich Schuchardta419d1d2018-08-31 21:31:32 +0200242out:
243 return EFI_EXIT(ret);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100244}
245
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200246/**
247 * efi_cout_test_string() - test writing Unicode string to console
248 *
249 * This function implements the TestString service of the simple text output
250 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
251 * for details.
252 *
253 * As in OutputString we simply convert UTF-16 to UTF-8 there are no unsupported
254 * code points and we can always return EFI_SUCCESS.
255 *
256 * @this: simple text output protocol
257 * @string: u16 string
258 * Return: status code
259 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100260static efi_status_t EFIAPI efi_cout_test_string(
261 struct efi_simple_text_output_protocol *this,
Heinrich Schuchardt84494282021-01-05 07:50:09 +0100262 const u16 *string)
Alexander Graf4aacacc2016-03-04 01:10:00 +0100263{
264 EFI_ENTRY("%p, %p", this, string);
265 return EFI_EXIT(EFI_SUCCESS);
266}
267
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200268/**
269 * cout_mode_matches() - check if mode has given terminal size
270 *
271 * @mode: text mode
272 * @rows: number of rows
273 * @cols: number of columns
274 * Return: true if number of rows and columns matches the mode and
275 * the mode is present
276 */
Emmanuel Vadota074d5d2016-11-08 06:03:29 +0100277static bool cout_mode_matches(struct cout_mode *mode, int rows, int cols)
278{
279 if (!mode->present)
280 return false;
281
282 return (mode->rows == rows) && (mode->columns == cols);
283}
284
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200285/**
Heinrich Schuchardtae165ef2021-03-16 12:56:57 +0100286 * query_console_serial() - query serial console size
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200287 *
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200288 * When using a serial console or the net console we can only devise the
289 * terminal size by querying the terminal using ECMA-48 control sequences.
290 *
Heinrich Schuchardtdc305ad2019-09-05 20:37:13 +0200291 * @rows: pointer to return number of rows
292 * @cols: pointer to return number of columns
293 * Returns: 0 on success
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200294 */
Rob Clark1e948922017-09-13 18:05:42 -0400295static int query_console_serial(int *rows, int *cols)
296{
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200297 int ret = 0;
298 int n[2];
Rob Clark1e948922017-09-13 18:05:42 -0400299
300 /* Empty input buffer */
301 while (tstc())
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200302 getchar();
Rob Clark1e948922017-09-13 18:05:42 -0400303
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200304 /*
305 * Not all terminals understand CSI [18t for querying the console size.
306 * We should adhere to escape sequences documented in the console_codes
Heinrich Schuchardt5e96f422018-10-18 21:51:38 +0200307 * man page and the ECMA-48 standard.
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200308 *
309 * So here we follow a different approach. We position the cursor to the
310 * bottom right and query its position. Before leaving the function we
311 * restore the original cursor position.
312 */
313 printf(ESC "7" /* Save cursor position */
314 ESC "[r" /* Set scrolling region to full window */
315 ESC "[999;999H" /* Move to bottom right corner */
316 ESC "[6n"); /* Query cursor position */
Rob Clark1e948922017-09-13 18:05:42 -0400317
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200318 /* Read {rows,cols} */
319 if (term_read_reply(n, 2, 'R')) {
320 ret = 1;
321 goto out;
322 }
Rob Clark1e948922017-09-13 18:05:42 -0400323
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200324 *cols = n[1];
325 *rows = n[0];
326out:
327 printf(ESC "8"); /* Restore cursor position */
328 return ret;
Rob Clark1e948922017-09-13 18:05:42 -0400329}
330
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200331/**
Heinrich Schuchardtae165ef2021-03-16 12:56:57 +0100332 * query_vidconsole() - query video console size
333 *
334 *
335 * @rows: pointer to return number of rows
336 * @cols: pointer to return number of columns
337 * Returns: 0 on success
338 */
339static int __maybe_unused query_vidconsole(int *rows, int *cols)
340{
341 const char *stdout_name = env_get("stdout");
342 struct stdio_dev *stdout_dev;
343 struct udevice *dev;
344 struct vidconsole_priv *priv;
345
346 if (!stdout_name || strncmp(stdout_name, "vidconsole", 10))
347 return -ENODEV;
348 stdout_dev = stdio_get_by_name("vidconsole");
349 if (!stdout_dev)
350 return -ENODEV;
351 dev = stdout_dev->priv;
352 if (!dev)
353 return -ENODEV;
354 priv = dev_get_uclass_priv(dev);
355 if (!priv)
356 return -ENODEV;
357 *rows = priv->rows;
358 *cols = priv->cols;
359 return 0;
360}
361
Heinrich Schuchardt761908e2022-06-14 08:02:03 +0200362void efi_setup_console_size(void)
Heinrich Schuchardt75b4e692018-04-29 20:02:46 +0200363{
Alexander Graf28795322018-06-03 15:51:17 +0200364 int rows = 25, cols = 80;
Heinrich Schuchardtae165ef2021-03-16 12:56:57 +0100365 int ret = -ENODEV;
Heinrich Schuchardt75b4e692018-04-29 20:02:46 +0200366
Simon Glass52cb5042022-10-18 07:46:31 -0600367 if (IS_ENABLED(CONFIG_VIDEO))
Heinrich Schuchardtae165ef2021-03-16 12:56:57 +0100368 ret = query_vidconsole(&rows, &cols);
Simon Glassab312512025-05-10 14:54:38 +0200369 if (ret) {
370 if (no_ansi)
371 ret = 0;
372 else
373 ret = query_console_serial(&rows, &cols);
374 }
Heinrich Schuchardtae165ef2021-03-16 12:56:57 +0100375 if (ret)
Heinrich Schuchardt75b4e692018-04-29 20:02:46 +0200376 return;
Heinrich Schuchardt75b4e692018-04-29 20:02:46 +0200377
Heinrich Schuchardt761908e2022-06-14 08:02:03 +0200378 log_debug("Console size %dx%d\n", rows, cols);
379
Heinrich Schuchardt75b4e692018-04-29 20:02:46 +0200380 /* Test if we can have Mode 1 */
381 if (cols >= 80 && rows >= 50) {
382 efi_cout_modes[1].present = 1;
383 efi_con_mode.max_mode = 2;
384 }
385
386 /*
387 * Install our mode as mode 2 if it is different
388 * than mode 0 or 1 and set it as the currently selected mode
389 */
390 if (!cout_mode_matches(&efi_cout_modes[0], rows, cols) &&
391 !cout_mode_matches(&efi_cout_modes[1], rows, cols)) {
392 efi_cout_modes[EFI_COUT_MODE_2].columns = cols;
393 efi_cout_modes[EFI_COUT_MODE_2].rows = rows;
394 efi_cout_modes[EFI_COUT_MODE_2].present = 1;
395 efi_con_mode.max_mode = EFI_MAX_COUT_MODE;
396 efi_con_mode.mode = EFI_COUT_MODE_2;
397 }
398}
399
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200400/**
401 * efi_cout_query_mode() - get terminal size for a text mode
402 *
403 * This function implements the QueryMode service of the simple text output
404 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
405 * for details.
406 *
407 * @this: simple text output protocol
408 * @mode_number: mode number to retrieve information on
409 * @columns: number of columns
410 * @rows: number of rows
411 * Return: status code
412 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100413static efi_status_t EFIAPI efi_cout_query_mode(
414 struct efi_simple_text_output_protocol *this,
415 unsigned long mode_number, unsigned long *columns,
416 unsigned long *rows)
417{
418 EFI_ENTRY("%p, %ld, %p, %p", this, mode_number, columns, rows);
419
Emmanuel Vadota074d5d2016-11-08 06:03:29 +0100420 if (mode_number >= efi_con_mode.max_mode)
421 return EFI_EXIT(EFI_UNSUPPORTED);
422
423 if (efi_cout_modes[mode_number].present != 1)
424 return EFI_EXIT(EFI_UNSUPPORTED);
425
Alexander Graf4aacacc2016-03-04 01:10:00 +0100426 if (columns)
Emmanuel Vadota074d5d2016-11-08 06:03:29 +0100427 *columns = efi_cout_modes[mode_number].columns;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100428 if (rows)
Emmanuel Vadota074d5d2016-11-08 06:03:29 +0100429 *rows = efi_cout_modes[mode_number].rows;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100430
431 return EFI_EXIT(EFI_SUCCESS);
432}
433
Rob Clark87ef0012017-10-10 08:23:01 -0400434static const struct {
435 unsigned int fg;
436 unsigned int bg;
437} color[] = {
438 { 30, 40 }, /* 0: black */
439 { 34, 44 }, /* 1: blue */
440 { 32, 42 }, /* 2: green */
441 { 36, 46 }, /* 3: cyan */
442 { 31, 41 }, /* 4: red */
443 { 35, 45 }, /* 5: magenta */
Heinrich Schuchardt6e8eff22018-09-08 19:57:24 +0200444 { 33, 43 }, /* 6: brown, map to yellow as EDK2 does*/
445 { 37, 47 }, /* 7: light gray, map to white */
Rob Clark87ef0012017-10-10 08:23:01 -0400446};
447
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200448/**
449 * efi_cout_set_attribute() - set fore- and background color
450 *
451 * This function implements the SetAttribute service of the simple text output
452 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
453 * for details.
454 *
455 * @this: simple text output protocol
456 * @attribute: foreground color - bits 0-3, background color - bits 4-6
457 * Return: status code
458 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100459static efi_status_t EFIAPI efi_cout_set_attribute(
460 struct efi_simple_text_output_protocol *this,
461 unsigned long attribute)
462{
Rob Clark87ef0012017-10-10 08:23:01 -0400463 unsigned int bold = EFI_ATTR_BOLD(attribute);
464 unsigned int fg = EFI_ATTR_FG(attribute);
465 unsigned int bg = EFI_ATTR_BG(attribute);
466
Alexander Graf4aacacc2016-03-04 01:10:00 +0100467 EFI_ENTRY("%p, %lx", this, attribute);
468
Heinrich Schuchardt1e129622019-06-14 07:16:57 +0200469 efi_con_mode.attribute = attribute;
Rob Clark87ef0012017-10-10 08:23:01 -0400470 if (attribute)
471 printf(ESC"[%u;%u;%um", bold, color[fg].fg, color[bg].bg);
472 else
473 printf(ESC"[0;37;40m");
474
475 return EFI_EXIT(EFI_SUCCESS);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100476}
477
Heinrich Schuchardt7995cbe2019-12-22 07:15:55 +0000478/**
Jan Kiszkad4d0fec2023-01-18 22:24:59 +0100479 * efi_clear_screen() - clear screen
Heinrich Schuchardta13136f2022-10-15 11:13:59 +0200480 */
481static void efi_clear_screen(void)
482{
Jan Kiszkad4d0fec2023-01-18 22:24:59 +0100483 if (CONFIG_IS_ENABLED(EFI_SCROLL_ON_CLEAR_SCREEN)) {
484 unsigned int row, screen_rows, screen_columns;
485
486 /* Avoid overwriting previous outputs on streaming consoles */
487 screen_rows = efi_cout_modes[efi_con_mode.mode].rows;
488 screen_columns = efi_cout_modes[efi_con_mode.mode].columns;
489 printf(ESC "[%u;%uH", screen_rows, screen_columns);
490 for (row = 1; row < screen_rows; row++)
491 printf("\n");
492 }
493
Heinrich Schuchardta13136f2022-10-15 11:13:59 +0200494 /*
495 * The Linux console wants both a clear and a home command. The video
496 * uclass does not support <ESC>[H without coordinates, yet.
497 */
498 printf(ESC "[2J" ESC "[1;1H");
499 efi_con_mode.cursor_column = 0;
500 efi_con_mode.cursor_row = 0;
501}
502
503/**
504 * efi_cout_clear_screen() - clear screen
Heinrich Schuchardt7995cbe2019-12-22 07:15:55 +0000505 *
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200506 * This function implements the ClearScreen service of the simple text output
507 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
508 * for details.
Heinrich Schuchardt7995cbe2019-12-22 07:15:55 +0000509 *
510 * @this: pointer to the protocol instance
511 * Return: status code
512 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100513static efi_status_t EFIAPI efi_cout_clear_screen(
514 struct efi_simple_text_output_protocol *this)
515{
516 EFI_ENTRY("%p", this);
517
Jan Kiszkafb181e22023-01-18 22:25:00 +0100518 /* Set default colors if not done yet */
519 if (efi_con_mode.attribute == 0) {
520 efi_con_mode.attribute = 0x07;
521 printf(ESC "[0;37;40m");
522 }
523
Heinrich Schuchardta13136f2022-10-15 11:13:59 +0200524 efi_clear_screen();
Alexander Graf4aacacc2016-03-04 01:10:00 +0100525
526 return EFI_EXIT(EFI_SUCCESS);
527}
528
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200529/**
530 * efi_cout_clear_set_mode() - set text model
531 *
532 * This function implements the SetMode service of the simple text output
533 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
534 * for details.
535 *
536 * @this: pointer to the protocol instance
537 * @mode_number: number of the text mode to set
538 * Return: status code
539 */
Heinrich Schuchardt757cc4a2019-06-14 07:20:51 +0200540static efi_status_t EFIAPI efi_cout_set_mode(
541 struct efi_simple_text_output_protocol *this,
542 unsigned long mode_number)
543{
544 EFI_ENTRY("%p, %ld", this, mode_number);
545
546 if (mode_number >= efi_con_mode.max_mode)
547 return EFI_EXIT(EFI_UNSUPPORTED);
Heinrich Schuchardt6a6afa72019-09-04 22:46:13 +0200548
549 if (!efi_cout_modes[mode_number].present)
550 return EFI_EXIT(EFI_UNSUPPORTED);
551
Heinrich Schuchardt757cc4a2019-06-14 07:20:51 +0200552 efi_con_mode.mode = mode_number;
Heinrich Schuchardta13136f2022-10-15 11:13:59 +0200553 efi_clear_screen();
Heinrich Schuchardt757cc4a2019-06-14 07:20:51 +0200554
555 return EFI_EXIT(EFI_SUCCESS);
556}
557
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200558/**
559 * efi_cout_reset() - reset the terminal
560 *
561 * This function implements the Reset service of the simple text output
562 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
563 * for details.
564 *
565 * @this: pointer to the protocol instance
566 * @extended_verification: if set an extended verification may be executed
567 * Return: status code
568 */
Heinrich Schuchardt09866c22018-07-05 19:58:07 +0200569static efi_status_t EFIAPI efi_cout_reset(
570 struct efi_simple_text_output_protocol *this,
571 char extended_verification)
572{
573 EFI_ENTRY("%p, %d", this, extended_verification);
574
Heinrich Schuchardt09866c22018-07-05 19:58:07 +0200575 /* Set default colors */
Heinrich Schuchardt1e129622019-06-14 07:16:57 +0200576 efi_con_mode.attribute = 0x07;
Heinrich Schuchardt09866c22018-07-05 19:58:07 +0200577 printf(ESC "[0;37;40m");
Heinrich Schuchardt30c9d672022-04-30 09:05:04 +0200578 /* Clear screen */
Heinrich Schuchardta13136f2022-10-15 11:13:59 +0200579 efi_clear_screen();
Heinrich Schuchardt09866c22018-07-05 19:58:07 +0200580
581 return EFI_EXIT(EFI_SUCCESS);
582}
583
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200584/**
585 * efi_cout_set_cursor_position() - reset the terminal
586 *
587 * This function implements the SetCursorPosition service of the simple text
588 * output protocol. See the Unified Extensible Firmware Interface (UEFI)
589 * specification for details.
590 *
591 * @this: pointer to the protocol instance
592 * @column: column to move to
593 * @row: row to move to
594 * Return: status code
595 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100596static efi_status_t EFIAPI efi_cout_set_cursor_position(
597 struct efi_simple_text_output_protocol *this,
598 unsigned long column, unsigned long row)
599{
Heinrich Schuchardtdcac1d92018-09-14 18:49:26 +0200600 efi_status_t ret = EFI_SUCCESS;
601 struct simple_text_output_mode *con = &efi_con_mode;
602 struct cout_mode *mode = &efi_cout_modes[con->mode];
603
Alexander Graf4aacacc2016-03-04 01:10:00 +0100604 EFI_ENTRY("%p, %ld, %ld", this, column, row);
605
Heinrich Schuchardtdcac1d92018-09-14 18:49:26 +0200606 /* Check parameters */
607 if (!this) {
608 ret = EFI_INVALID_PARAMETER;
609 goto out;
610 }
611 if (row >= mode->rows || column >= mode->columns) {
612 ret = EFI_UNSUPPORTED;
613 goto out;
614 }
615
616 /*
617 * Set cursor position by sending CSI H.
618 * EFI origin is [0, 0], terminal origin is [1, 1].
619 */
620 printf(ESC "[%d;%dH", (int)row + 1, (int)column + 1);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100621 efi_con_mode.cursor_column = column;
622 efi_con_mode.cursor_row = row;
Heinrich Schuchardtdcac1d92018-09-14 18:49:26 +0200623out:
624 return EFI_EXIT(ret);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100625}
626
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200627/**
628 * efi_cout_enable_cursor() - enable the cursor
629 *
630 * This function implements the EnableCursor service of the simple text output
631 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
632 * for details.
633 *
634 * @this: pointer to the protocol instance
635 * @enable: if true enable, if false disable the cursor
636 * Return: status code
637 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100638static efi_status_t EFIAPI efi_cout_enable_cursor(
639 struct efi_simple_text_output_protocol *this,
640 bool enable)
641{
642 EFI_ENTRY("%p, %d", this, enable);
643
644 printf(ESC"[?25%c", enable ? 'h' : 'l');
Heinrich Schuchardt53f26b92019-06-02 22:54:28 +0200645 efi_con_mode.cursor_visible = !!enable;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100646
647 return EFI_EXIT(EFI_SUCCESS);
648}
649
Heinrich Schuchardt580c13b2017-10-26 19:25:59 +0200650struct efi_simple_text_output_protocol efi_con_out = {
Alexander Graf4aacacc2016-03-04 01:10:00 +0100651 .reset = efi_cout_reset,
652 .output_string = efi_cout_output_string,
653 .test_string = efi_cout_test_string,
654 .query_mode = efi_cout_query_mode,
655 .set_mode = efi_cout_set_mode,
656 .set_attribute = efi_cout_set_attribute,
657 .clear_screen = efi_cout_clear_screen,
658 .set_cursor_position = efi_cout_set_cursor_position,
659 .enable_cursor = efi_cout_enable_cursor,
660 .mode = (void*)&efi_con_mode,
661};
662
Heinrich Schuchardt695691e2018-09-11 22:38:12 +0200663/**
664 * struct efi_cin_notify_function - registered console input notify function
665 *
666 * @link: link to list
Heinrich Schuchardtdc305ad2019-09-05 20:37:13 +0200667 * @key: key to notify
Heinrich Schuchardt695691e2018-09-11 22:38:12 +0200668 * @function: function to call
669 */
670struct efi_cin_notify_function {
671 struct list_head link;
672 struct efi_key_data key;
673 efi_status_t (EFIAPI *function)
674 (struct efi_key_data *key_data);
675};
676
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200677static bool key_available;
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200678static struct efi_key_data next_key;
Heinrich Schuchardt695691e2018-09-11 22:38:12 +0200679static LIST_HEAD(cin_notify_functions);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100680
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200681/**
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200682 * set_shift_mask() - set shift mask
683 *
684 * @mod: Xterm shift mask
Heinrich Schuchardtdc305ad2019-09-05 20:37:13 +0200685 * @key_state: receives the state of the shift, alt, control, and logo keys
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200686 */
Heinrich Schuchardtf2e7d002023-02-10 08:51:41 +0100687static void set_shift_mask(int mod, struct efi_key_state *key_state)
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200688{
689 key_state->key_shift_state = EFI_SHIFT_STATE_VALID;
690 if (mod) {
691 --mod;
692 if (mod & 1)
693 key_state->key_shift_state |= EFI_LEFT_SHIFT_PRESSED;
694 if (mod & 2)
695 key_state->key_shift_state |= EFI_LEFT_ALT_PRESSED;
696 if (mod & 4)
697 key_state->key_shift_state |= EFI_LEFT_CONTROL_PRESSED;
Heinrich Schuchardtfea93d62019-06-16 22:33:20 +0200698 if (!mod || (mod & 8))
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200699 key_state->key_shift_state |= EFI_LEFT_LOGO_PRESSED;
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200700 }
701}
702
703/**
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200704 * analyze_modifiers() - analyze modifiers (shift, alt, ctrl) for function keys
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200705 *
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100706 * This gets called when we have already parsed CSI.
707 *
Heinrich Schuchardtdc305ad2019-09-05 20:37:13 +0200708 * @key_state: receives the state of the shift, alt, control, and logo keys
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200709 * Return: the unmodified code
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100710 */
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200711static int analyze_modifiers(struct efi_key_state *key_state)
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100712{
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200713 int c, mod = 0, ret = 0;
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100714
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200715 c = getchar();
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100716
717 if (c != ';') {
718 ret = c;
719 if (c == '~')
720 goto out;
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200721 c = getchar();
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100722 }
723 for (;;) {
724 switch (c) {
725 case '0'...'9':
726 mod *= 10;
727 mod += c - '0';
728 /* fall through */
729 case ';':
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200730 c = getchar();
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100731 break;
732 default:
733 goto out;
734 }
735 }
736out:
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200737 set_shift_mask(mod, key_state);
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100738 if (!ret)
739 ret = c;
740 return ret;
741}
742
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200743/**
744 * efi_cin_read_key() - read a key from the console input
745 *
746 * @key: - key received
747 * Return: - status code
748 */
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200749static efi_status_t efi_cin_read_key(struct efi_key_data *key)
Alexander Graf4aacacc2016-03-04 01:10:00 +0100750{
751 struct efi_input_key pressed_key = {
752 .scan_code = 0,
753 .unicode_char = 0,
754 };
Heinrich Schuchardtfc5f1a12018-09-12 00:05:32 +0200755 s32 ch;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100756
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200757 if (console_read_unicode(&ch))
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200758 return EFI_NOT_READY;
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200759
760 key->key_state.key_shift_state = EFI_SHIFT_STATE_INVALID;
761 key->key_state.key_toggle_state = EFI_TOGGLE_STATE_INVALID;
762
Heinrich Schuchardtfc5f1a12018-09-12 00:05:32 +0200763 /* We do not support multi-word codes */
764 if (ch >= 0x10000)
765 ch = '?';
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200766
767 switch (ch) {
768 case 0x1b:
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100769 /*
Heinrich Schuchardte5c93172020-12-27 14:47:50 +0100770 * If a second key is received within 10 ms, assume that we are
771 * dealing with an escape sequence. Otherwise consider this the
772 * escape key being hit. 10 ms is long enough to work fine at
773 * 1200 baud and above.
774 */
775 udelay(10000);
776 if (!tstc()) {
777 pressed_key.scan_code = 23;
778 break;
779 }
780 /*
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100781 * Xterm Control Sequences
782 * https://www.xfree86.org/4.8.0/ctlseqs.html
783 */
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200784 ch = getchar();
Alexander Graf4aacacc2016-03-04 01:10:00 +0100785 switch (ch) {
786 case cESC: /* ESC */
787 pressed_key.scan_code = 23;
788 break;
Heinrich Schuchardt46e41d02019-06-16 21:41:13 +0200789 case 'O': /* F1 - F4, End */
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200790 ch = getchar();
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200791 /* consider modifiers */
Heinrich Schuchardt46e41d02019-06-16 21:41:13 +0200792 if (ch == 'F') { /* End */
793 pressed_key.scan_code = 6;
794 break;
795 } else if (ch < 'P') {
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200796 set_shift_mask(ch - '0', &key->key_state);
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200797 ch = getchar();
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200798 }
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100799 pressed_key.scan_code = ch - 'P' + 11;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100800 break;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100801 case '[':
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200802 ch = getchar();
Alexander Graf4aacacc2016-03-04 01:10:00 +0100803 switch (ch) {
804 case 'A'...'D': /* up, down right, left */
805 pressed_key.scan_code = ch - 'A' + 1;
806 break;
807 case 'F': /* End */
808 pressed_key.scan_code = 6;
809 break;
810 case 'H': /* Home */
811 pressed_key.scan_code = 5;
812 break;
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100813 case '1':
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200814 ch = analyze_modifiers(&key->key_state);
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100815 switch (ch) {
816 case '1'...'5': /* F1 - F5 */
817 pressed_key.scan_code = ch - '1' + 11;
818 break;
Heinrich Schuchardt46e41d02019-06-16 21:41:13 +0200819 case '6'...'9': /* F5 - F8 */
820 pressed_key.scan_code = ch - '6' + 15;
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100821 break;
822 case 'A'...'D': /* up, down right, left */
823 pressed_key.scan_code = ch - 'A' + 1;
824 break;
Heinrich Schuchardt46e41d02019-06-16 21:41:13 +0200825 case 'F': /* End */
826 pressed_key.scan_code = 6;
827 break;
828 case 'H': /* Home */
829 pressed_key.scan_code = 5;
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100830 break;
Heinrich Schuchardt46e41d02019-06-16 21:41:13 +0200831 case '~': /* Home */
832 pressed_key.scan_code = 5;
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100833 break;
834 }
Alexander Graf4aacacc2016-03-04 01:10:00 +0100835 break;
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100836 case '2':
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200837 ch = analyze_modifiers(&key->key_state);
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100838 switch (ch) {
839 case '0'...'1': /* F9 - F10 */
840 pressed_key.scan_code = ch - '0' + 19;
841 break;
842 case '3'...'4': /* F11 - F12 */
843 pressed_key.scan_code = ch - '3' + 21;
844 break;
845 case '~': /* INS */
846 pressed_key.scan_code = 7;
847 break;
848 }
Alexander Graf4aacacc2016-03-04 01:10:00 +0100849 break;
850 case '3': /* DEL */
851 pressed_key.scan_code = 8;
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200852 analyze_modifiers(&key->key_state);
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100853 break;
854 case '5': /* PG UP */
855 pressed_key.scan_code = 9;
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200856 analyze_modifiers(&key->key_state);
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100857 break;
858 case '6': /* PG DOWN */
859 pressed_key.scan_code = 10;
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200860 analyze_modifiers(&key->key_state);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100861 break;
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200862 } /* [ */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100863 break;
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200864 default:
865 /* ALT key */
866 set_shift_mask(3, &key->key_state);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100867 }
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200868 break;
869 case 0x7f:
Alexander Graf4aacacc2016-03-04 01:10:00 +0100870 /* Backspace */
871 ch = 0x08;
872 }
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200873 if (pressed_key.scan_code) {
874 key->key_state.key_shift_state |= EFI_SHIFT_STATE_VALID;
875 } else {
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100876 pressed_key.unicode_char = ch;
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200877
878 /*
879 * Assume left control key for control characters typically
880 * entered using the control key.
881 */
882 if (ch >= 0x01 && ch <= 0x1f) {
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200883 key->key_state.key_shift_state |=
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200884 EFI_SHIFT_STATE_VALID;
885 switch (ch) {
886 case 0x01 ... 0x07:
887 case 0x0b ... 0x0c:
888 case 0x0e ... 0x1f:
889 key->key_state.key_shift_state |=
890 EFI_LEFT_CONTROL_PRESSED;
891 }
892 }
893 }
894 key->key = pressed_key;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100895
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200896 return EFI_SUCCESS;
897}
898
899/**
Heinrich Schuchardt695691e2018-09-11 22:38:12 +0200900 * efi_cin_notify() - notify registered functions
901 */
902static void efi_cin_notify(void)
903{
904 struct efi_cin_notify_function *item;
905
906 list_for_each_entry(item, &cin_notify_functions, link) {
907 bool match = true;
908
909 /* We do not support toggle states */
910 if (item->key.key.unicode_char || item->key.key.scan_code) {
911 if (item->key.key.unicode_char !=
912 next_key.key.unicode_char ||
913 item->key.key.scan_code != next_key.key.scan_code)
914 match = false;
915 }
916 if (item->key.key_state.key_shift_state &&
917 item->key.key_state.key_shift_state !=
918 next_key.key_state.key_shift_state)
919 match = false;
920
921 if (match)
922 /* We don't bother about the return code */
923 EFI_CALL(item->function(&next_key));
924 }
925}
926
927/**
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200928 * efi_cin_check() - check if keyboard input is available
929 */
930static void efi_cin_check(void)
931{
932 efi_status_t ret;
933
934 if (key_available) {
Heinrich Schuchardt7b4b8d862019-06-07 06:47:01 +0200935 efi_signal_event(efi_con_in.wait_for_key);
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200936 return;
937 }
938
939 if (tstc()) {
940 ret = efi_cin_read_key(&next_key);
941 if (ret == EFI_SUCCESS) {
942 key_available = true;
943
Heinrich Schuchardt695691e2018-09-11 22:38:12 +0200944 /* Notify registered functions */
945 efi_cin_notify();
946
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200947 /* Queue the wait for key event */
Heinrich Schuchardt695691e2018-09-11 22:38:12 +0200948 if (key_available)
Heinrich Schuchardt7b4b8d862019-06-07 06:47:01 +0200949 efi_signal_event(efi_con_in.wait_for_key);
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200950 }
951 }
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200952}
953
954/**
955 * efi_cin_empty_buffer() - empty input buffer
956 */
957static void efi_cin_empty_buffer(void)
958{
959 while (tstc())
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200960 getchar();
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200961 key_available = false;
962}
963
964/**
965 * efi_cin_reset_ex() - reset console input
966 *
967 * @this: - the extended simple text input protocol
968 * @extended_verification: - extended verification
969 *
970 * This function implements the reset service of the
971 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
972 *
973 * See the Unified Extensible Firmware Interface (UEFI) specification for
974 * details.
975 *
976 * Return: old value of the task priority level
977 */
978static efi_status_t EFIAPI efi_cin_reset_ex(
979 struct efi_simple_text_input_ex_protocol *this,
980 bool extended_verification)
981{
982 efi_status_t ret = EFI_SUCCESS;
983
984 EFI_ENTRY("%p, %d", this, extended_verification);
985
986 /* Check parameters */
987 if (!this) {
988 ret = EFI_INVALID_PARAMETER;
989 goto out;
990 }
991
992 efi_cin_empty_buffer();
993out:
994 return EFI_EXIT(ret);
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200995}
996
997/**
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200998 * efi_cin_read_key_stroke_ex() - read key stroke
999 *
1000 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
1001 * @key_data: key read from console
1002 * Return: status code
1003 *
1004 * This function implements the ReadKeyStrokeEx service of the
1005 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
1006 *
1007 * See the Unified Extensible Firmware Interface (UEFI) specification for
1008 * details.
1009 */
1010static efi_status_t EFIAPI efi_cin_read_key_stroke_ex(
1011 struct efi_simple_text_input_ex_protocol *this,
1012 struct efi_key_data *key_data)
1013{
1014 efi_status_t ret = EFI_SUCCESS;
1015
1016 EFI_ENTRY("%p, %p", this, key_data);
1017
1018 /* Check parameters */
1019 if (!this || !key_data) {
1020 ret = EFI_INVALID_PARAMETER;
1021 goto out;
1022 }
1023
1024 /* We don't do interrupts, so check for timers cooperatively */
1025 efi_timer_check();
1026
1027 /* Enable console input after ExitBootServices */
1028 efi_cin_check();
1029
1030 if (!key_available) {
Heinrich Schuchardtb6697c22022-09-01 23:30:09 +02001031 memset(key_data, 0, sizeof(struct efi_key_data));
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001032 ret = EFI_NOT_READY;
1033 goto out;
1034 }
Heinrich Schuchardt00b00a12019-04-06 20:59:24 +02001035 /*
1036 * CTRL+A - CTRL+Z have to be signaled as a - z.
1037 * SHIFT+CTRL+A - SHIFT+CTRL+Z have to be signaled as A - Z.
Heinrich Schuchardt068dc9c2022-09-02 00:49:12 +02001038 * CTRL+\ - CTRL+_ have to be signaled as \ - _.
Heinrich Schuchardt00b00a12019-04-06 20:59:24 +02001039 */
1040 switch (next_key.key.unicode_char) {
1041 case 0x01 ... 0x07:
1042 case 0x0b ... 0x0c:
1043 case 0x0e ... 0x1a:
1044 if (!(next_key.key_state.key_toggle_state &
1045 EFI_CAPS_LOCK_ACTIVE) ^
1046 !(next_key.key_state.key_shift_state &
1047 (EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED)))
1048 next_key.key.unicode_char += 0x40;
1049 else
1050 next_key.key.unicode_char += 0x60;
Heinrich Schuchardt068dc9c2022-09-02 00:49:12 +02001051 break;
1052 case 0x1c ... 0x1f:
1053 next_key.key.unicode_char += 0x40;
Heinrich Schuchardt00b00a12019-04-06 20:59:24 +02001054 }
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001055 *key_data = next_key;
1056 key_available = false;
1057 efi_con_in.wait_for_key->is_signaled = false;
Heinrich Schuchardt00b00a12019-04-06 20:59:24 +02001058
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001059out:
1060 return EFI_EXIT(ret);
1061}
1062
1063/**
1064 * efi_cin_set_state() - set toggle key state
1065 *
1066 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
Heinrich Schuchardta41ccf92019-05-18 17:07:52 +02001067 * @key_toggle_state: pointer to key toggle state
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001068 * Return: status code
1069 *
1070 * This function implements the SetState service of the
1071 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
1072 *
1073 * See the Unified Extensible Firmware Interface (UEFI) specification for
1074 * details.
1075 */
1076static efi_status_t EFIAPI efi_cin_set_state(
1077 struct efi_simple_text_input_ex_protocol *this,
Heinrich Schuchardta41ccf92019-05-18 17:07:52 +02001078 u8 *key_toggle_state)
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001079{
Heinrich Schuchardta41ccf92019-05-18 17:07:52 +02001080 EFI_ENTRY("%p, %p", this, key_toggle_state);
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001081 /*
1082 * U-Boot supports multiple console input sources like serial and
1083 * net console for which a key toggle state cannot be set at all.
1084 *
1085 * According to the UEFI specification it is allowable to not implement
1086 * this service.
1087 */
1088 return EFI_EXIT(EFI_UNSUPPORTED);
1089}
1090
1091/**
1092 * efi_cin_register_key_notify() - register key notification function
1093 *
1094 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
1095 * @key_data: key to be notified
1096 * @key_notify_function: function to be called if the key is pressed
1097 * @notify_handle: handle for unregistering the notification
1098 * Return: status code
1099 *
1100 * This function implements the SetState service of the
1101 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
1102 *
1103 * See the Unified Extensible Firmware Interface (UEFI) specification for
1104 * details.
1105 */
1106static efi_status_t EFIAPI efi_cin_register_key_notify(
1107 struct efi_simple_text_input_ex_protocol *this,
1108 struct efi_key_data *key_data,
1109 efi_status_t (EFIAPI *key_notify_function)(
1110 struct efi_key_data *key_data),
1111 void **notify_handle)
1112{
Heinrich Schuchardt695691e2018-09-11 22:38:12 +02001113 efi_status_t ret = EFI_SUCCESS;
1114 struct efi_cin_notify_function *notify_function;
1115
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001116 EFI_ENTRY("%p, %p, %p, %p",
1117 this, key_data, key_notify_function, notify_handle);
Heinrich Schuchardt695691e2018-09-11 22:38:12 +02001118
1119 /* Check parameters */
1120 if (!this || !key_data || !key_notify_function || !notify_handle) {
1121 ret = EFI_INVALID_PARAMETER;
1122 goto out;
1123 }
1124
1125 EFI_PRINT("u+%04x, sc %04x, sh %08x, tg %02x\n",
1126 key_data->key.unicode_char,
1127 key_data->key.scan_code,
1128 key_data->key_state.key_shift_state,
1129 key_data->key_state.key_toggle_state);
1130
1131 notify_function = calloc(1, sizeof(struct efi_cin_notify_function));
1132 if (!notify_function) {
1133 ret = EFI_OUT_OF_RESOURCES;
1134 goto out;
1135 }
1136 notify_function->key = *key_data;
1137 notify_function->function = key_notify_function;
1138 list_add_tail(&notify_function->link, &cin_notify_functions);
1139 *notify_handle = notify_function;
1140out:
1141 return EFI_EXIT(ret);
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001142}
1143
1144/**
1145 * efi_cin_unregister_key_notify() - unregister key notification function
1146 *
1147 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
1148 * @notification_handle: handle received when registering
1149 * Return: status code
1150 *
1151 * This function implements the SetState service of the
1152 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
1153 *
1154 * See the Unified Extensible Firmware Interface (UEFI) specification for
1155 * details.
1156 */
1157static efi_status_t EFIAPI efi_cin_unregister_key_notify(
1158 struct efi_simple_text_input_ex_protocol *this,
1159 void *notification_handle)
1160{
Heinrich Schuchardt695691e2018-09-11 22:38:12 +02001161 efi_status_t ret = EFI_INVALID_PARAMETER;
1162 struct efi_cin_notify_function *item, *notify_function =
1163 notification_handle;
1164
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001165 EFI_ENTRY("%p, %p", this, notification_handle);
Heinrich Schuchardt695691e2018-09-11 22:38:12 +02001166
1167 /* Check parameters */
1168 if (!this || !notification_handle)
1169 goto out;
1170
1171 list_for_each_entry(item, &cin_notify_functions, link) {
1172 if (item == notify_function) {
1173 ret = EFI_SUCCESS;
1174 break;
1175 }
1176 }
1177 if (ret != EFI_SUCCESS)
1178 goto out;
1179
1180 /* Remove the notify function */
1181 list_del(&notify_function->link);
1182 free(notify_function);
1183out:
1184 return EFI_EXIT(ret);
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001185}
1186
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001187/**
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001188 * efi_cin_reset() - drain the input buffer
1189 *
1190 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
1191 * @extended_verification: allow for exhaustive verification
1192 * Return: status code
1193 *
1194 * This function implements the Reset service of the
1195 * EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
1196 *
1197 * See the Unified Extensible Firmware Interface (UEFI) specification for
1198 * details.
1199 */
1200static efi_status_t EFIAPI efi_cin_reset
1201 (struct efi_simple_text_input_protocol *this,
1202 bool extended_verification)
1203{
1204 efi_status_t ret = EFI_SUCCESS;
1205
1206 EFI_ENTRY("%p, %d", this, extended_verification);
1207
1208 /* Check parameters */
1209 if (!this) {
1210 ret = EFI_INVALID_PARAMETER;
1211 goto out;
1212 }
1213
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001214 efi_cin_empty_buffer();
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001215out:
1216 return EFI_EXIT(ret);
1217}
1218
1219/**
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001220 * efi_cin_read_key_stroke() - read key stroke
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001221 *
1222 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
1223 * @key: key read from console
1224 * Return: status code
1225 *
1226 * This function implements the ReadKeyStroke service of the
1227 * EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
1228 *
1229 * See the Unified Extensible Firmware Interface (UEFI) specification for
1230 * details.
1231 */
1232static efi_status_t EFIAPI efi_cin_read_key_stroke
1233 (struct efi_simple_text_input_protocol *this,
1234 struct efi_input_key *key)
1235{
1236 efi_status_t ret = EFI_SUCCESS;
1237
1238 EFI_ENTRY("%p, %p", this, key);
1239
1240 /* Check parameters */
1241 if (!this || !key) {
1242 ret = EFI_INVALID_PARAMETER;
1243 goto out;
1244 }
1245
1246 /* We don't do interrupts, so check for timers cooperatively */
1247 efi_timer_check();
1248
1249 /* Enable console input after ExitBootServices */
1250 efi_cin_check();
1251
1252 if (!key_available) {
1253 ret = EFI_NOT_READY;
1254 goto out;
1255 }
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001256 *key = next_key.key;
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001257 key_available = false;
1258 efi_con_in.wait_for_key->is_signaled = false;
1259out:
1260 return EFI_EXIT(ret);
Alexander Graf4aacacc2016-03-04 01:10:00 +01001261}
1262
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001263static struct efi_simple_text_input_ex_protocol efi_con_in_ex = {
1264 .reset = efi_cin_reset_ex,
1265 .read_key_stroke_ex = efi_cin_read_key_stroke_ex,
1266 .wait_for_key_ex = NULL,
1267 .set_state = efi_cin_set_state,
1268 .register_key_notify = efi_cin_register_key_notify,
1269 .unregister_key_notify = efi_cin_unregister_key_notify,
1270};
1271
Heinrich Schuchardt3dabffd2018-09-08 10:20:10 +02001272struct efi_simple_text_input_protocol efi_con_in = {
Alexander Graf4aacacc2016-03-04 01:10:00 +01001273 .reset = efi_cin_reset,
1274 .read_key_stroke = efi_cin_read_key_stroke,
1275 .wait_for_key = NULL,
1276};
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001277
1278static struct efi_event *console_timer_event;
1279
Heinrich Schuchardtd8b878a2018-01-19 20:24:51 +01001280/*
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001281 * efi_console_timer_notify() - notify the console timer event
Heinrich Schuchardtd8b878a2018-01-19 20:24:51 +01001282 *
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001283 * @event: console timer event
1284 * @context: not used
Heinrich Schuchardtd8b878a2018-01-19 20:24:51 +01001285 */
xypron.glpk@gmx.de0ce42dc2017-07-20 05:26:07 +02001286static void EFIAPI efi_console_timer_notify(struct efi_event *event,
1287 void *context)
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001288{
1289 EFI_ENTRY("%p, %p", event, context);
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001290 efi_cin_check();
1291 EFI_EXIT(EFI_SUCCESS);
1292}
Heinrich Schuchardtd8b878a2018-01-19 20:24:51 +01001293
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001294/**
1295 * efi_key_notify() - notify the wait for key event
1296 *
1297 * @event: wait for key event
1298 * @context: not used
1299 */
1300static void EFIAPI efi_key_notify(struct efi_event *event, void *context)
1301{
1302 EFI_ENTRY("%p, %p", event, context);
1303 efi_cin_check();
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001304 EFI_EXIT(EFI_SUCCESS);
1305}
1306
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001307/**
1308 * efi_console_register() - install the console protocols
1309 *
1310 * This function is called from do_bootefi_exec().
Heinrich Schuchardta92e9ab2018-10-02 06:08:26 +02001311 *
1312 * Return: status code
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001313 */
Heinrich Schuchardta92e9ab2018-10-02 06:08:26 +02001314efi_status_t efi_console_register(void)
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001315{
1316 efi_status_t r;
Heinrich Schuchardt81244ea2022-02-04 20:47:09 +01001317 struct efi_device_path *dp;
Rob Clark49f7b4b2017-07-24 10:39:01 -04001318
Heinrich Schuchardt81244ea2022-02-04 20:47:09 +01001319 /* Install protocols on root node */
Ilias Apalodimas8ac0ebe2022-10-06 16:08:46 +03001320 r = efi_install_multiple_protocol_interfaces(&efi_root,
1321 &efi_guid_text_output_protocol,
1322 &efi_con_out,
1323 &efi_guid_text_input_protocol,
1324 &efi_con_in,
1325 &efi_guid_text_input_ex_protocol,
1326 &efi_con_in_ex,
1327 NULL);
Alexander Graf36bab912018-09-04 14:59:11 +02001328
Heinrich Schuchardt81244ea2022-02-04 20:47:09 +01001329 /* Create console node and install device path protocols */
1330 if (CONFIG_IS_ENABLED(DM_SERIAL)) {
1331 dp = efi_dp_from_uart();
1332 if (!dp)
1333 goto out_of_memory;
Alexander Graf36bab912018-09-04 14:59:11 +02001334
Heinrich Schuchardt81244ea2022-02-04 20:47:09 +01001335 /* Hook UART up to the device list */
1336 efi_add_handle(&uart_obj);
Alexander Graf36bab912018-09-04 14:59:11 +02001337
Heinrich Schuchardt81244ea2022-02-04 20:47:09 +01001338 /* Install device path */
1339 r = efi_add_protocol(&uart_obj, &efi_guid_device_path, dp);
1340 if (r != EFI_SUCCESS)
1341 goto out_of_memory;
1342 }
Rob Clark49f7b4b2017-07-24 10:39:01 -04001343
Heinrich Schuchardt580c13b2017-10-26 19:25:59 +02001344 /* Create console events */
Heinrich Schuchardtbf7f1692018-02-18 15:17:52 +01001345 r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK, efi_key_notify,
1346 NULL, NULL, &efi_con_in.wait_for_key);
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001347 if (r != EFI_SUCCESS) {
1348 printf("ERROR: Failed to register WaitForKey event\n");
1349 return r;
1350 }
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001351 efi_con_in_ex.wait_for_key_ex = efi_con_in.wait_for_key;
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001352 r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
Heinrich Schuchardtbf7f1692018-02-18 15:17:52 +01001353 efi_console_timer_notify, NULL, NULL,
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001354 &console_timer_event);
1355 if (r != EFI_SUCCESS) {
1356 printf("ERROR: Failed to register console event\n");
1357 return r;
1358 }
1359 /* 5000 ns cycle is sufficient for 2 MBaud */
1360 r = efi_set_timer(console_timer_event, EFI_TIMER_PERIODIC, 50);
1361 if (r != EFI_SUCCESS)
1362 printf("ERROR: Failed to set console timer\n");
1363 return r;
Heinrich Schuchardt580c13b2017-10-26 19:25:59 +02001364out_of_memory:
Heinrich Schuchardt6e8eff22018-09-08 19:57:24 +02001365 printf("ERROR: Out of memory\n");
Heinrich Schuchardt580c13b2017-10-26 19:25:59 +02001366 return r;
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001367}
Masahisa Kojimac5ff0a02022-09-12 17:33:50 +09001368
1369/**
1370 * efi_console_get_u16_string() - get user input string
1371 *
1372 * @cin: protocol interface to EFI_SIMPLE_TEXT_INPUT_PROTOCOL
1373 * @buf: buffer to store user input string in UTF16
1374 * @count: number of u16 string including NULL terminator that buf has
1375 * @filter_func: callback to filter user input
1376 * @row: row number to locate user input form
1377 * @col: column number to locate user input form
1378 * Return: status code
1379 */
1380efi_status_t efi_console_get_u16_string(struct efi_simple_text_input_protocol *cin,
1381 u16 *buf, efi_uintn_t count,
1382 efi_console_filter_func filter_func,
1383 int row, int col)
1384{
1385 efi_status_t ret;
1386 efi_uintn_t len = 0;
1387 struct efi_input_key key;
1388
1389 printf(ANSI_CURSOR_POSITION
1390 ANSI_CLEAR_LINE_TO_END
1391 ANSI_CURSOR_SHOW, row, col);
1392
Heinrich Schuchardt49dbcaf2022-10-15 12:22:37 +02001393 efi_cin_empty_buffer();
Masahisa Kojimac5ff0a02022-09-12 17:33:50 +09001394
1395 for (;;) {
1396 do {
1397 ret = EFI_CALL(cin->read_key_stroke(cin, &key));
1398 mdelay(10);
1399 } while (ret == EFI_NOT_READY);
1400
1401 if (key.unicode_char == u'\b') {
1402 if (len > 0)
1403 buf[--len] = u'\0';
1404
1405 printf(ANSI_CURSOR_POSITION
1406 "%ls"
1407 ANSI_CLEAR_LINE_TO_END, row, col, buf);
1408 continue;
1409 } else if (key.unicode_char == u'\r') {
1410 buf[len] = u'\0';
1411 return EFI_SUCCESS;
1412 } else if (key.unicode_char == 0x3 || key.scan_code == 23) {
1413 return EFI_ABORTED;
1414 } else if (key.unicode_char < 0x20) {
1415 /* ignore control codes other than Ctrl+C, '\r' and '\b' */
1416 continue;
1417 } else if (key.scan_code != 0) {
1418 /* only accept single ESC press for cancel */
1419 continue;
1420 }
1421
1422 if (filter_func) {
1423 if (filter_func(&key) != EFI_SUCCESS)
1424 continue;
1425 }
1426
1427 if (len >= (count - 1))
1428 continue;
1429
1430 buf[len] = key.unicode_char;
1431 len++;
1432 printf(ANSI_CURSOR_POSITION "%ls", row, col, buf);
1433 }
1434}