blob: c944c10b216263cbd1baefa34410acb8de94657e [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
Emmanuel Vadota074d5d2016-11-08 06:03:29 +010033static struct cout_mode efi_cout_modes[] = {
34 /* EFI Mode 0 is 80x25 and always present */
35 {
36 .columns = 80,
37 .rows = 25,
38 .present = 1,
39 },
40 /* EFI Mode 1 is always 80x50 */
41 {
42 .columns = 80,
43 .rows = 50,
44 .present = 0,
45 },
46 /* Value are unknown until we query the console */
47 {
48 .columns = 0,
49 .rows = 0,
50 .present = 0,
51 },
52};
53
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +020054const efi_guid_t efi_guid_text_input_ex_protocol =
55 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
Heinrich Schuchardt580c13b2017-10-26 19:25:59 +020056const efi_guid_t efi_guid_text_input_protocol =
57 EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID;
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +020058const efi_guid_t efi_guid_text_output_protocol =
59 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID;
Alexander Graf4aacacc2016-03-04 01:10:00 +010060
61#define cESC '\x1b'
62#define ESC "\x1b"
63
Heinrich Schuchardt761908e2022-06-14 08:02:03 +020064/*
65 * efi_con_mode - mode information of the Simple Text Output Protocol
66 *
67 * Use safe settings before efi_setup_console_size() is called.
68 * By default enable only the 80x25 mode which must always exist.
69 */
Alexander Graf4aacacc2016-03-04 01:10:00 +010070static struct simple_text_output_mode efi_con_mode = {
Emmanuel Vadota074d5d2016-11-08 06:03:29 +010071 .max_mode = 1,
Alexander Graf4aacacc2016-03-04 01:10:00 +010072 .mode = 0,
73 .attribute = 0,
74 .cursor_column = 0,
75 .cursor_row = 0,
76 .cursor_visible = 1,
77};
78
Heinrich Schuchardtef6c69e2023-03-03 22:04:26 +010079/**
80 * term_get_char() - read a character from the console
81 *
82 * Wait for up to 100 ms to read a character from the console.
83 *
84 * @c: pointer to the buffer to receive the character
85 * Return: 0 on success, 1 otherwise
86 */
Matthias Brugger29c6f5f2019-03-05 12:50:18 +010087static int term_get_char(s32 *c)
88{
89 u64 timeout;
90
91 /* Wait up to 100 ms for a character */
92 timeout = timer_get_us() + 100000;
93
94 while (!tstc())
95 if (timer_get_us() > timeout)
96 return 1;
97
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +020098 *c = getchar();
Matthias Brugger29c6f5f2019-03-05 12:50:18 +010099 return 0;
100}
101
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200102/**
Heinrich Schuchardt77135c22018-05-16 18:17:38 +0200103 * Receive and parse a reply from the terminal.
104 *
105 * @n: array of return values
106 * @num: number of return values expected
107 * @end_char: character indicating end of terminal message
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200108 * Return: non-zero indicates error
Heinrich Schuchardt77135c22018-05-16 18:17:38 +0200109 */
110static int term_read_reply(int *n, int num, char end_char)
Alexander Graf4aacacc2016-03-04 01:10:00 +0100111{
Matthias Brugger29c6f5f2019-03-05 12:50:18 +0100112 s32 c;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100113 int i = 0;
114
Matthias Brugger29c6f5f2019-03-05 12:50:18 +0100115 if (term_get_char(&c) || c != cESC)
Alexander Graf4aacacc2016-03-04 01:10:00 +0100116 return -1;
Matthias Brugger29c6f5f2019-03-05 12:50:18 +0100117
118 if (term_get_char(&c) || c != '[')
Alexander Graf4aacacc2016-03-04 01:10:00 +0100119 return -1;
120
121 n[0] = 0;
122 while (1) {
Matthias Brugger29c6f5f2019-03-05 12:50:18 +0100123 if (!term_get_char(&c)) {
124 if (c == ';') {
125 i++;
126 if (i >= num)
127 return -1;
128 n[i] = 0;
129 continue;
130 } else if (c == end_char) {
131 break;
132 } else if (c > '9' || c < '0') {
Alexander Graf4aacacc2016-03-04 01:10:00 +0100133 return -1;
Matthias Brugger29c6f5f2019-03-05 12:50:18 +0100134 }
135
136 /* Read one more decimal position */
137 n[i] *= 10;
138 n[i] += c - '0';
139 } else {
Alexander Graf4aacacc2016-03-04 01:10:00 +0100140 return -1;
141 }
Alexander Graf4aacacc2016-03-04 01:10:00 +0100142 }
Heinrich Schuchardt77135c22018-05-16 18:17:38 +0200143 if (i != num - 1)
144 return -1;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100145
146 return 0;
147}
148
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200149/**
150 * efi_cout_output_string() - write Unicode string to console
151 *
152 * This function implements the OutputString service of the simple text output
153 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
154 * for details.
155 *
156 * @this: simple text output protocol
157 * @string: u16 string
158 * Return: status code
159 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100160static efi_status_t EFIAPI efi_cout_output_string(
161 struct efi_simple_text_output_protocol *this,
Heinrich Schuchardt84494282021-01-05 07:50:09 +0100162 const u16 *string)
Alexander Graf4aacacc2016-03-04 01:10:00 +0100163{
Rob Clark1ef185d2017-09-13 18:05:44 -0400164 struct simple_text_output_mode *con = &efi_con_mode;
165 struct cout_mode *mode = &efi_cout_modes[con->mode];
Heinrich Schuchardta419d1d2018-08-31 21:31:32 +0200166 char *buf, *pos;
Heinrich Schuchardt84494282021-01-05 07:50:09 +0100167 const u16 *p;
Heinrich Schuchardta419d1d2018-08-31 21:31:32 +0200168 efi_status_t ret = EFI_SUCCESS;
Rob Clark1ef185d2017-09-13 18:05:44 -0400169
Heinrich Schuchardta419d1d2018-08-31 21:31:32 +0200170 EFI_ENTRY("%p, %p", this, string);
Rob Clark1ef185d2017-09-13 18:05:44 -0400171
Heinrich Schuchardte60b2982019-05-18 18:11:54 +0200172 if (!this || !string) {
173 ret = EFI_INVALID_PARAMETER;
174 goto out;
175 }
176
Heinrich Schuchardta419d1d2018-08-31 21:31:32 +0200177 buf = malloc(utf16_utf8_strlen(string) + 1);
178 if (!buf) {
179 ret = EFI_OUT_OF_RESOURCES;
180 goto out;
181 }
182 pos = buf;
183 utf16_utf8_strcpy(&pos, string);
Rob Clark1ef185d2017-09-13 18:05:44 -0400184 fputs(stdout, buf);
Heinrich Schuchardta419d1d2018-08-31 21:31:32 +0200185 free(buf);
Rob Clark1ef185d2017-09-13 18:05:44 -0400186
Heinrich Schuchardt8aaeed92018-04-29 16:24:25 +0200187 /*
188 * Update the cursor position.
189 *
190 * The UEFI spec provides advance rules for U+0000, U+0008, U+000A,
Heinrich Schuchardtda88da82019-09-04 21:13:45 +0200191 * and U000D. All other control characters are ignored. Any non-control
192 * character increase the column by one.
Heinrich Schuchardt8aaeed92018-04-29 16:24:25 +0200193 */
194 for (p = string; *p; ++p) {
Rob Clark1ef185d2017-09-13 18:05:44 -0400195 switch (*p) {
Heinrich Schuchardt8aaeed92018-04-29 16:24:25 +0200196 case '\b': /* U+0008, backspace */
Heinrich Schuchardtda88da82019-09-04 21:13:45 +0200197 if (con->cursor_column)
198 con->cursor_column--;
Rob Clark1ef185d2017-09-13 18:05:44 -0400199 break;
Heinrich Schuchardt8aaeed92018-04-29 16:24:25 +0200200 case '\n': /* U+000A, newline */
Rob Clark1ef185d2017-09-13 18:05:44 -0400201 con->cursor_column = 0;
202 con->cursor_row++;
203 break;
Heinrich Schuchardt8aaeed92018-04-29 16:24:25 +0200204 case '\r': /* U+000D, carriage-return */
205 con->cursor_column = 0;
Rob Clark1ef185d2017-09-13 18:05:44 -0400206 break;
Heinrich Schuchardt8aaeed92018-04-29 16:24:25 +0200207 case 0xd800 ... 0xdbff:
208 /*
209 * Ignore high surrogates, we do not want to count a
210 * Unicode character twice.
211 */
Rob Clark1ef185d2017-09-13 18:05:44 -0400212 break;
213 default:
Heinrich Schuchardtda88da82019-09-04 21:13:45 +0200214 /* Exclude control codes */
215 if (*p > 0x1f)
216 con->cursor_column++;
Rob Clark1ef185d2017-09-13 18:05:44 -0400217 break;
218 }
219 if (con->cursor_column >= mode->columns) {
220 con->cursor_column = 0;
221 con->cursor_row++;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100222 }
Heinrich Schuchardtda88da82019-09-04 21:13:45 +0200223 /*
224 * When we exceed the row count the terminal will scroll up one
225 * line. We have to adjust the cursor position.
226 */
227 if (con->cursor_row >= mode->rows && con->cursor_row)
228 con->cursor_row--;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100229 }
230
Heinrich Schuchardta419d1d2018-08-31 21:31:32 +0200231out:
232 return EFI_EXIT(ret);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100233}
234
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200235/**
236 * efi_cout_test_string() - test writing Unicode string to console
237 *
238 * This function implements the TestString service of the simple text output
239 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
240 * for details.
241 *
242 * As in OutputString we simply convert UTF-16 to UTF-8 there are no unsupported
243 * code points and we can always return EFI_SUCCESS.
244 *
245 * @this: simple text output protocol
246 * @string: u16 string
247 * Return: status code
248 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100249static efi_status_t EFIAPI efi_cout_test_string(
250 struct efi_simple_text_output_protocol *this,
Heinrich Schuchardt84494282021-01-05 07:50:09 +0100251 const u16 *string)
Alexander Graf4aacacc2016-03-04 01:10:00 +0100252{
253 EFI_ENTRY("%p, %p", this, string);
254 return EFI_EXIT(EFI_SUCCESS);
255}
256
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200257/**
258 * cout_mode_matches() - check if mode has given terminal size
259 *
260 * @mode: text mode
261 * @rows: number of rows
262 * @cols: number of columns
263 * Return: true if number of rows and columns matches the mode and
264 * the mode is present
265 */
Emmanuel Vadota074d5d2016-11-08 06:03:29 +0100266static bool cout_mode_matches(struct cout_mode *mode, int rows, int cols)
267{
268 if (!mode->present)
269 return false;
270
271 return (mode->rows == rows) && (mode->columns == cols);
272}
273
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200274/**
Heinrich Schuchardtae165ef2021-03-16 12:56:57 +0100275 * query_console_serial() - query serial console size
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200276 *
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200277 * When using a serial console or the net console we can only devise the
278 * terminal size by querying the terminal using ECMA-48 control sequences.
279 *
Heinrich Schuchardtdc305ad2019-09-05 20:37:13 +0200280 * @rows: pointer to return number of rows
281 * @cols: pointer to return number of columns
282 * Returns: 0 on success
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200283 */
Rob Clark1e948922017-09-13 18:05:42 -0400284static int query_console_serial(int *rows, int *cols)
285{
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200286 int ret = 0;
287 int n[2];
Rob Clark1e948922017-09-13 18:05:42 -0400288
289 /* Empty input buffer */
290 while (tstc())
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200291 getchar();
Rob Clark1e948922017-09-13 18:05:42 -0400292
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200293 /*
294 * Not all terminals understand CSI [18t for querying the console size.
295 * We should adhere to escape sequences documented in the console_codes
Heinrich Schuchardt5e96f422018-10-18 21:51:38 +0200296 * man page and the ECMA-48 standard.
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200297 *
298 * So here we follow a different approach. We position the cursor to the
299 * bottom right and query its position. Before leaving the function we
300 * restore the original cursor position.
301 */
302 printf(ESC "7" /* Save cursor position */
303 ESC "[r" /* Set scrolling region to full window */
304 ESC "[999;999H" /* Move to bottom right corner */
305 ESC "[6n"); /* Query cursor position */
Rob Clark1e948922017-09-13 18:05:42 -0400306
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200307 /* Read {rows,cols} */
308 if (term_read_reply(n, 2, 'R')) {
309 ret = 1;
310 goto out;
311 }
Rob Clark1e948922017-09-13 18:05:42 -0400312
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200313 *cols = n[1];
314 *rows = n[0];
315out:
316 printf(ESC "8"); /* Restore cursor position */
317 return ret;
Rob Clark1e948922017-09-13 18:05:42 -0400318}
319
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200320/**
Heinrich Schuchardtae165ef2021-03-16 12:56:57 +0100321 * query_vidconsole() - query video console size
322 *
323 *
324 * @rows: pointer to return number of rows
325 * @cols: pointer to return number of columns
326 * Returns: 0 on success
327 */
328static int __maybe_unused query_vidconsole(int *rows, int *cols)
329{
330 const char *stdout_name = env_get("stdout");
331 struct stdio_dev *stdout_dev;
332 struct udevice *dev;
333 struct vidconsole_priv *priv;
334
335 if (!stdout_name || strncmp(stdout_name, "vidconsole", 10))
336 return -ENODEV;
337 stdout_dev = stdio_get_by_name("vidconsole");
338 if (!stdout_dev)
339 return -ENODEV;
340 dev = stdout_dev->priv;
341 if (!dev)
342 return -ENODEV;
343 priv = dev_get_uclass_priv(dev);
344 if (!priv)
345 return -ENODEV;
346 *rows = priv->rows;
347 *cols = priv->cols;
348 return 0;
349}
350
351/**
Heinrich Schuchardt761908e2022-06-14 08:02:03 +0200352 * efi_setup_console_size() - update the mode table.
Heinrich Schuchardt75b4e692018-04-29 20:02:46 +0200353 *
354 * By default the only mode available is 80x25. If the console has at least 50
355 * lines, enable mode 80x50. If we can query the console size and it is neither
356 * 80x25 nor 80x50, set it as an additional mode.
357 */
Heinrich Schuchardt761908e2022-06-14 08:02:03 +0200358void efi_setup_console_size(void)
Heinrich Schuchardt75b4e692018-04-29 20:02:46 +0200359{
Alexander Graf28795322018-06-03 15:51:17 +0200360 int rows = 25, cols = 80;
Heinrich Schuchardtae165ef2021-03-16 12:56:57 +0100361 int ret = -ENODEV;
Heinrich Schuchardt75b4e692018-04-29 20:02:46 +0200362
Simon Glass52cb5042022-10-18 07:46:31 -0600363 if (IS_ENABLED(CONFIG_VIDEO))
Heinrich Schuchardtae165ef2021-03-16 12:56:57 +0100364 ret = query_vidconsole(&rows, &cols);
365 if (ret)
366 ret = query_console_serial(&rows, &cols);
367 if (ret)
Heinrich Schuchardt75b4e692018-04-29 20:02:46 +0200368 return;
Heinrich Schuchardt75b4e692018-04-29 20:02:46 +0200369
Heinrich Schuchardt761908e2022-06-14 08:02:03 +0200370 log_debug("Console size %dx%d\n", rows, cols);
371
Heinrich Schuchardt75b4e692018-04-29 20:02:46 +0200372 /* Test if we can have Mode 1 */
373 if (cols >= 80 && rows >= 50) {
374 efi_cout_modes[1].present = 1;
375 efi_con_mode.max_mode = 2;
376 }
377
378 /*
379 * Install our mode as mode 2 if it is different
380 * than mode 0 or 1 and set it as the currently selected mode
381 */
382 if (!cout_mode_matches(&efi_cout_modes[0], rows, cols) &&
383 !cout_mode_matches(&efi_cout_modes[1], rows, cols)) {
384 efi_cout_modes[EFI_COUT_MODE_2].columns = cols;
385 efi_cout_modes[EFI_COUT_MODE_2].rows = rows;
386 efi_cout_modes[EFI_COUT_MODE_2].present = 1;
387 efi_con_mode.max_mode = EFI_MAX_COUT_MODE;
388 efi_con_mode.mode = EFI_COUT_MODE_2;
389 }
390}
391
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200392/**
393 * efi_cout_query_mode() - get terminal size for a text mode
394 *
395 * This function implements the QueryMode service of the simple text output
396 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
397 * for details.
398 *
399 * @this: simple text output protocol
400 * @mode_number: mode number to retrieve information on
401 * @columns: number of columns
402 * @rows: number of rows
403 * Return: status code
404 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100405static efi_status_t EFIAPI efi_cout_query_mode(
406 struct efi_simple_text_output_protocol *this,
407 unsigned long mode_number, unsigned long *columns,
408 unsigned long *rows)
409{
410 EFI_ENTRY("%p, %ld, %p, %p", this, mode_number, columns, rows);
411
Emmanuel Vadota074d5d2016-11-08 06:03:29 +0100412 if (mode_number >= efi_con_mode.max_mode)
413 return EFI_EXIT(EFI_UNSUPPORTED);
414
415 if (efi_cout_modes[mode_number].present != 1)
416 return EFI_EXIT(EFI_UNSUPPORTED);
417
Alexander Graf4aacacc2016-03-04 01:10:00 +0100418 if (columns)
Emmanuel Vadota074d5d2016-11-08 06:03:29 +0100419 *columns = efi_cout_modes[mode_number].columns;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100420 if (rows)
Emmanuel Vadota074d5d2016-11-08 06:03:29 +0100421 *rows = efi_cout_modes[mode_number].rows;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100422
423 return EFI_EXIT(EFI_SUCCESS);
424}
425
Rob Clark87ef0012017-10-10 08:23:01 -0400426static const struct {
427 unsigned int fg;
428 unsigned int bg;
429} color[] = {
430 { 30, 40 }, /* 0: black */
431 { 34, 44 }, /* 1: blue */
432 { 32, 42 }, /* 2: green */
433 { 36, 46 }, /* 3: cyan */
434 { 31, 41 }, /* 4: red */
435 { 35, 45 }, /* 5: magenta */
Heinrich Schuchardt6e8eff22018-09-08 19:57:24 +0200436 { 33, 43 }, /* 6: brown, map to yellow as EDK2 does*/
437 { 37, 47 }, /* 7: light gray, map to white */
Rob Clark87ef0012017-10-10 08:23:01 -0400438};
439
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200440/**
441 * efi_cout_set_attribute() - set fore- and background color
442 *
443 * This function implements the SetAttribute service of the simple text output
444 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
445 * for details.
446 *
447 * @this: simple text output protocol
448 * @attribute: foreground color - bits 0-3, background color - bits 4-6
449 * Return: status code
450 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100451static efi_status_t EFIAPI efi_cout_set_attribute(
452 struct efi_simple_text_output_protocol *this,
453 unsigned long attribute)
454{
Rob Clark87ef0012017-10-10 08:23:01 -0400455 unsigned int bold = EFI_ATTR_BOLD(attribute);
456 unsigned int fg = EFI_ATTR_FG(attribute);
457 unsigned int bg = EFI_ATTR_BG(attribute);
458
Alexander Graf4aacacc2016-03-04 01:10:00 +0100459 EFI_ENTRY("%p, %lx", this, attribute);
460
Heinrich Schuchardt1e129622019-06-14 07:16:57 +0200461 efi_con_mode.attribute = attribute;
Rob Clark87ef0012017-10-10 08:23:01 -0400462 if (attribute)
463 printf(ESC"[%u;%u;%um", bold, color[fg].fg, color[bg].bg);
464 else
465 printf(ESC"[0;37;40m");
466
467 return EFI_EXIT(EFI_SUCCESS);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100468}
469
Heinrich Schuchardt7995cbe2019-12-22 07:15:55 +0000470/**
Jan Kiszkad4d0fec2023-01-18 22:24:59 +0100471 * efi_clear_screen() - clear screen
Heinrich Schuchardta13136f2022-10-15 11:13:59 +0200472 */
473static void efi_clear_screen(void)
474{
Jan Kiszkad4d0fec2023-01-18 22:24:59 +0100475 if (CONFIG_IS_ENABLED(EFI_SCROLL_ON_CLEAR_SCREEN)) {
476 unsigned int row, screen_rows, screen_columns;
477
478 /* Avoid overwriting previous outputs on streaming consoles */
479 screen_rows = efi_cout_modes[efi_con_mode.mode].rows;
480 screen_columns = efi_cout_modes[efi_con_mode.mode].columns;
481 printf(ESC "[%u;%uH", screen_rows, screen_columns);
482 for (row = 1; row < screen_rows; row++)
483 printf("\n");
484 }
485
Heinrich Schuchardta13136f2022-10-15 11:13:59 +0200486 /*
487 * The Linux console wants both a clear and a home command. The video
488 * uclass does not support <ESC>[H without coordinates, yet.
489 */
490 printf(ESC "[2J" ESC "[1;1H");
491 efi_con_mode.cursor_column = 0;
492 efi_con_mode.cursor_row = 0;
493}
494
495/**
496 * efi_cout_clear_screen() - clear screen
Heinrich Schuchardt7995cbe2019-12-22 07:15:55 +0000497 *
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200498 * This function implements the ClearScreen service of the simple text output
499 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
500 * for details.
Heinrich Schuchardt7995cbe2019-12-22 07:15:55 +0000501 *
502 * @this: pointer to the protocol instance
503 * Return: status code
504 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100505static efi_status_t EFIAPI efi_cout_clear_screen(
506 struct efi_simple_text_output_protocol *this)
507{
508 EFI_ENTRY("%p", this);
509
Jan Kiszkafb181e22023-01-18 22:25:00 +0100510 /* Set default colors if not done yet */
511 if (efi_con_mode.attribute == 0) {
512 efi_con_mode.attribute = 0x07;
513 printf(ESC "[0;37;40m");
514 }
515
Heinrich Schuchardta13136f2022-10-15 11:13:59 +0200516 efi_clear_screen();
Alexander Graf4aacacc2016-03-04 01:10:00 +0100517
518 return EFI_EXIT(EFI_SUCCESS);
519}
520
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200521/**
522 * efi_cout_clear_set_mode() - set text model
523 *
524 * This function implements the SetMode service of the simple text output
525 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
526 * for details.
527 *
528 * @this: pointer to the protocol instance
529 * @mode_number: number of the text mode to set
530 * Return: status code
531 */
Heinrich Schuchardt757cc4a2019-06-14 07:20:51 +0200532static efi_status_t EFIAPI efi_cout_set_mode(
533 struct efi_simple_text_output_protocol *this,
534 unsigned long mode_number)
535{
536 EFI_ENTRY("%p, %ld", this, mode_number);
537
538 if (mode_number >= efi_con_mode.max_mode)
539 return EFI_EXIT(EFI_UNSUPPORTED);
Heinrich Schuchardt6a6afa72019-09-04 22:46:13 +0200540
541 if (!efi_cout_modes[mode_number].present)
542 return EFI_EXIT(EFI_UNSUPPORTED);
543
Heinrich Schuchardt757cc4a2019-06-14 07:20:51 +0200544 efi_con_mode.mode = mode_number;
Heinrich Schuchardta13136f2022-10-15 11:13:59 +0200545 efi_clear_screen();
Heinrich Schuchardt757cc4a2019-06-14 07:20:51 +0200546
547 return EFI_EXIT(EFI_SUCCESS);
548}
549
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200550/**
551 * efi_cout_reset() - reset the terminal
552 *
553 * This function implements the Reset 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 * @extended_verification: if set an extended verification may be executed
559 * Return: status code
560 */
Heinrich Schuchardt09866c22018-07-05 19:58:07 +0200561static efi_status_t EFIAPI efi_cout_reset(
562 struct efi_simple_text_output_protocol *this,
563 char extended_verification)
564{
565 EFI_ENTRY("%p, %d", this, extended_verification);
566
Heinrich Schuchardt09866c22018-07-05 19:58:07 +0200567 /* Set default colors */
Heinrich Schuchardt1e129622019-06-14 07:16:57 +0200568 efi_con_mode.attribute = 0x07;
Heinrich Schuchardt09866c22018-07-05 19:58:07 +0200569 printf(ESC "[0;37;40m");
Heinrich Schuchardt30c9d672022-04-30 09:05:04 +0200570 /* Clear screen */
Heinrich Schuchardta13136f2022-10-15 11:13:59 +0200571 efi_clear_screen();
Heinrich Schuchardt09866c22018-07-05 19:58:07 +0200572
573 return EFI_EXIT(EFI_SUCCESS);
574}
575
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200576/**
577 * efi_cout_set_cursor_position() - reset the terminal
578 *
579 * This function implements the SetCursorPosition service of the simple text
580 * output protocol. See the Unified Extensible Firmware Interface (UEFI)
581 * specification for details.
582 *
583 * @this: pointer to the protocol instance
584 * @column: column to move to
585 * @row: row to move to
586 * Return: status code
587 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100588static efi_status_t EFIAPI efi_cout_set_cursor_position(
589 struct efi_simple_text_output_protocol *this,
590 unsigned long column, unsigned long row)
591{
Heinrich Schuchardtdcac1d92018-09-14 18:49:26 +0200592 efi_status_t ret = EFI_SUCCESS;
593 struct simple_text_output_mode *con = &efi_con_mode;
594 struct cout_mode *mode = &efi_cout_modes[con->mode];
595
Alexander Graf4aacacc2016-03-04 01:10:00 +0100596 EFI_ENTRY("%p, %ld, %ld", this, column, row);
597
Heinrich Schuchardtdcac1d92018-09-14 18:49:26 +0200598 /* Check parameters */
599 if (!this) {
600 ret = EFI_INVALID_PARAMETER;
601 goto out;
602 }
603 if (row >= mode->rows || column >= mode->columns) {
604 ret = EFI_UNSUPPORTED;
605 goto out;
606 }
607
608 /*
609 * Set cursor position by sending CSI H.
610 * EFI origin is [0, 0], terminal origin is [1, 1].
611 */
612 printf(ESC "[%d;%dH", (int)row + 1, (int)column + 1);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100613 efi_con_mode.cursor_column = column;
614 efi_con_mode.cursor_row = row;
Heinrich Schuchardtdcac1d92018-09-14 18:49:26 +0200615out:
616 return EFI_EXIT(ret);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100617}
618
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200619/**
620 * efi_cout_enable_cursor() - enable the cursor
621 *
622 * This function implements the EnableCursor service of the simple text output
623 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
624 * for details.
625 *
626 * @this: pointer to the protocol instance
627 * @enable: if true enable, if false disable the cursor
628 * Return: status code
629 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100630static efi_status_t EFIAPI efi_cout_enable_cursor(
631 struct efi_simple_text_output_protocol *this,
632 bool enable)
633{
634 EFI_ENTRY("%p, %d", this, enable);
635
636 printf(ESC"[?25%c", enable ? 'h' : 'l');
Heinrich Schuchardt53f26b92019-06-02 22:54:28 +0200637 efi_con_mode.cursor_visible = !!enable;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100638
639 return EFI_EXIT(EFI_SUCCESS);
640}
641
Heinrich Schuchardt580c13b2017-10-26 19:25:59 +0200642struct efi_simple_text_output_protocol efi_con_out = {
Alexander Graf4aacacc2016-03-04 01:10:00 +0100643 .reset = efi_cout_reset,
644 .output_string = efi_cout_output_string,
645 .test_string = efi_cout_test_string,
646 .query_mode = efi_cout_query_mode,
647 .set_mode = efi_cout_set_mode,
648 .set_attribute = efi_cout_set_attribute,
649 .clear_screen = efi_cout_clear_screen,
650 .set_cursor_position = efi_cout_set_cursor_position,
651 .enable_cursor = efi_cout_enable_cursor,
652 .mode = (void*)&efi_con_mode,
653};
654
Heinrich Schuchardt695691e2018-09-11 22:38:12 +0200655/**
656 * struct efi_cin_notify_function - registered console input notify function
657 *
658 * @link: link to list
Heinrich Schuchardtdc305ad2019-09-05 20:37:13 +0200659 * @key: key to notify
Heinrich Schuchardt695691e2018-09-11 22:38:12 +0200660 * @function: function to call
661 */
662struct efi_cin_notify_function {
663 struct list_head link;
664 struct efi_key_data key;
665 efi_status_t (EFIAPI *function)
666 (struct efi_key_data *key_data);
667};
668
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200669static bool key_available;
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200670static struct efi_key_data next_key;
Heinrich Schuchardt695691e2018-09-11 22:38:12 +0200671static LIST_HEAD(cin_notify_functions);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100672
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200673/**
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200674 * set_shift_mask() - set shift mask
675 *
676 * @mod: Xterm shift mask
Heinrich Schuchardtdc305ad2019-09-05 20:37:13 +0200677 * @key_state: receives the state of the shift, alt, control, and logo keys
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200678 */
Heinrich Schuchardtf2e7d002023-02-10 08:51:41 +0100679static void set_shift_mask(int mod, struct efi_key_state *key_state)
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200680{
681 key_state->key_shift_state = EFI_SHIFT_STATE_VALID;
682 if (mod) {
683 --mod;
684 if (mod & 1)
685 key_state->key_shift_state |= EFI_LEFT_SHIFT_PRESSED;
686 if (mod & 2)
687 key_state->key_shift_state |= EFI_LEFT_ALT_PRESSED;
688 if (mod & 4)
689 key_state->key_shift_state |= EFI_LEFT_CONTROL_PRESSED;
Heinrich Schuchardtfea93d62019-06-16 22:33:20 +0200690 if (!mod || (mod & 8))
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200691 key_state->key_shift_state |= EFI_LEFT_LOGO_PRESSED;
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200692 }
693}
694
695/**
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200696 * analyze_modifiers() - analyze modifiers (shift, alt, ctrl) for function keys
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200697 *
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100698 * This gets called when we have already parsed CSI.
699 *
Heinrich Schuchardtdc305ad2019-09-05 20:37:13 +0200700 * @key_state: receives the state of the shift, alt, control, and logo keys
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200701 * Return: the unmodified code
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100702 */
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200703static int analyze_modifiers(struct efi_key_state *key_state)
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100704{
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200705 int c, mod = 0, ret = 0;
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100706
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200707 c = getchar();
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100708
709 if (c != ';') {
710 ret = c;
711 if (c == '~')
712 goto out;
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200713 c = getchar();
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100714 }
715 for (;;) {
716 switch (c) {
717 case '0'...'9':
718 mod *= 10;
719 mod += c - '0';
720 /* fall through */
721 case ';':
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200722 c = getchar();
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100723 break;
724 default:
725 goto out;
726 }
727 }
728out:
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200729 set_shift_mask(mod, key_state);
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100730 if (!ret)
731 ret = c;
732 return ret;
733}
734
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200735/**
736 * efi_cin_read_key() - read a key from the console input
737 *
738 * @key: - key received
739 * Return: - status code
740 */
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200741static efi_status_t efi_cin_read_key(struct efi_key_data *key)
Alexander Graf4aacacc2016-03-04 01:10:00 +0100742{
743 struct efi_input_key pressed_key = {
744 .scan_code = 0,
745 .unicode_char = 0,
746 };
Heinrich Schuchardtfc5f1a12018-09-12 00:05:32 +0200747 s32 ch;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100748
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200749 if (console_read_unicode(&ch))
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200750 return EFI_NOT_READY;
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200751
752 key->key_state.key_shift_state = EFI_SHIFT_STATE_INVALID;
753 key->key_state.key_toggle_state = EFI_TOGGLE_STATE_INVALID;
754
Heinrich Schuchardtfc5f1a12018-09-12 00:05:32 +0200755 /* We do not support multi-word codes */
756 if (ch >= 0x10000)
757 ch = '?';
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200758
759 switch (ch) {
760 case 0x1b:
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100761 /*
Heinrich Schuchardte5c93172020-12-27 14:47:50 +0100762 * If a second key is received within 10 ms, assume that we are
763 * dealing with an escape sequence. Otherwise consider this the
764 * escape key being hit. 10 ms is long enough to work fine at
765 * 1200 baud and above.
766 */
767 udelay(10000);
768 if (!tstc()) {
769 pressed_key.scan_code = 23;
770 break;
771 }
772 /*
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100773 * Xterm Control Sequences
774 * https://www.xfree86.org/4.8.0/ctlseqs.html
775 */
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200776 ch = getchar();
Alexander Graf4aacacc2016-03-04 01:10:00 +0100777 switch (ch) {
778 case cESC: /* ESC */
779 pressed_key.scan_code = 23;
780 break;
Heinrich Schuchardt46e41d02019-06-16 21:41:13 +0200781 case 'O': /* F1 - F4, End */
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200782 ch = getchar();
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200783 /* consider modifiers */
Heinrich Schuchardt46e41d02019-06-16 21:41:13 +0200784 if (ch == 'F') { /* End */
785 pressed_key.scan_code = 6;
786 break;
787 } else if (ch < 'P') {
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200788 set_shift_mask(ch - '0', &key->key_state);
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200789 ch = getchar();
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200790 }
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100791 pressed_key.scan_code = ch - 'P' + 11;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100792 break;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100793 case '[':
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200794 ch = getchar();
Alexander Graf4aacacc2016-03-04 01:10:00 +0100795 switch (ch) {
796 case 'A'...'D': /* up, down right, left */
797 pressed_key.scan_code = ch - 'A' + 1;
798 break;
799 case 'F': /* End */
800 pressed_key.scan_code = 6;
801 break;
802 case 'H': /* Home */
803 pressed_key.scan_code = 5;
804 break;
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100805 case '1':
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200806 ch = analyze_modifiers(&key->key_state);
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100807 switch (ch) {
808 case '1'...'5': /* F1 - F5 */
809 pressed_key.scan_code = ch - '1' + 11;
810 break;
Heinrich Schuchardt46e41d02019-06-16 21:41:13 +0200811 case '6'...'9': /* F5 - F8 */
812 pressed_key.scan_code = ch - '6' + 15;
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100813 break;
814 case 'A'...'D': /* up, down right, left */
815 pressed_key.scan_code = ch - 'A' + 1;
816 break;
Heinrich Schuchardt46e41d02019-06-16 21:41:13 +0200817 case 'F': /* End */
818 pressed_key.scan_code = 6;
819 break;
820 case 'H': /* Home */
821 pressed_key.scan_code = 5;
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100822 break;
Heinrich Schuchardt46e41d02019-06-16 21:41:13 +0200823 case '~': /* Home */
824 pressed_key.scan_code = 5;
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100825 break;
826 }
Alexander Graf4aacacc2016-03-04 01:10:00 +0100827 break;
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100828 case '2':
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200829 ch = analyze_modifiers(&key->key_state);
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100830 switch (ch) {
831 case '0'...'1': /* F9 - F10 */
832 pressed_key.scan_code = ch - '0' + 19;
833 break;
834 case '3'...'4': /* F11 - F12 */
835 pressed_key.scan_code = ch - '3' + 21;
836 break;
837 case '~': /* INS */
838 pressed_key.scan_code = 7;
839 break;
840 }
Alexander Graf4aacacc2016-03-04 01:10:00 +0100841 break;
842 case '3': /* DEL */
843 pressed_key.scan_code = 8;
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200844 analyze_modifiers(&key->key_state);
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100845 break;
846 case '5': /* PG UP */
847 pressed_key.scan_code = 9;
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200848 analyze_modifiers(&key->key_state);
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100849 break;
850 case '6': /* PG DOWN */
851 pressed_key.scan_code = 10;
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200852 analyze_modifiers(&key->key_state);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100853 break;
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200854 } /* [ */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100855 break;
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200856 default:
857 /* ALT key */
858 set_shift_mask(3, &key->key_state);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100859 }
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200860 break;
861 case 0x7f:
Alexander Graf4aacacc2016-03-04 01:10:00 +0100862 /* Backspace */
863 ch = 0x08;
864 }
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200865 if (pressed_key.scan_code) {
866 key->key_state.key_shift_state |= EFI_SHIFT_STATE_VALID;
867 } else {
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100868 pressed_key.unicode_char = ch;
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200869
870 /*
871 * Assume left control key for control characters typically
872 * entered using the control key.
873 */
874 if (ch >= 0x01 && ch <= 0x1f) {
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200875 key->key_state.key_shift_state |=
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200876 EFI_SHIFT_STATE_VALID;
877 switch (ch) {
878 case 0x01 ... 0x07:
879 case 0x0b ... 0x0c:
880 case 0x0e ... 0x1f:
881 key->key_state.key_shift_state |=
882 EFI_LEFT_CONTROL_PRESSED;
883 }
884 }
885 }
886 key->key = pressed_key;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100887
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200888 return EFI_SUCCESS;
889}
890
891/**
Heinrich Schuchardt695691e2018-09-11 22:38:12 +0200892 * efi_cin_notify() - notify registered functions
893 */
894static void efi_cin_notify(void)
895{
896 struct efi_cin_notify_function *item;
897
898 list_for_each_entry(item, &cin_notify_functions, link) {
899 bool match = true;
900
901 /* We do not support toggle states */
902 if (item->key.key.unicode_char || item->key.key.scan_code) {
903 if (item->key.key.unicode_char !=
904 next_key.key.unicode_char ||
905 item->key.key.scan_code != next_key.key.scan_code)
906 match = false;
907 }
908 if (item->key.key_state.key_shift_state &&
909 item->key.key_state.key_shift_state !=
910 next_key.key_state.key_shift_state)
911 match = false;
912
913 if (match)
914 /* We don't bother about the return code */
915 EFI_CALL(item->function(&next_key));
916 }
917}
918
919/**
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200920 * efi_cin_check() - check if keyboard input is available
921 */
922static void efi_cin_check(void)
923{
924 efi_status_t ret;
925
926 if (key_available) {
Heinrich Schuchardt7b4b8d862019-06-07 06:47:01 +0200927 efi_signal_event(efi_con_in.wait_for_key);
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200928 return;
929 }
930
931 if (tstc()) {
932 ret = efi_cin_read_key(&next_key);
933 if (ret == EFI_SUCCESS) {
934 key_available = true;
935
Heinrich Schuchardt695691e2018-09-11 22:38:12 +0200936 /* Notify registered functions */
937 efi_cin_notify();
938
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200939 /* Queue the wait for key event */
Heinrich Schuchardt695691e2018-09-11 22:38:12 +0200940 if (key_available)
Heinrich Schuchardt7b4b8d862019-06-07 06:47:01 +0200941 efi_signal_event(efi_con_in.wait_for_key);
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200942 }
943 }
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200944}
945
946/**
947 * efi_cin_empty_buffer() - empty input buffer
948 */
949static void efi_cin_empty_buffer(void)
950{
951 while (tstc())
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200952 getchar();
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200953 key_available = false;
954}
955
956/**
957 * efi_cin_reset_ex() - reset console input
958 *
959 * @this: - the extended simple text input protocol
960 * @extended_verification: - extended verification
961 *
962 * This function implements the reset service of the
963 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
964 *
965 * See the Unified Extensible Firmware Interface (UEFI) specification for
966 * details.
967 *
968 * Return: old value of the task priority level
969 */
970static efi_status_t EFIAPI efi_cin_reset_ex(
971 struct efi_simple_text_input_ex_protocol *this,
972 bool extended_verification)
973{
974 efi_status_t ret = EFI_SUCCESS;
975
976 EFI_ENTRY("%p, %d", this, extended_verification);
977
978 /* Check parameters */
979 if (!this) {
980 ret = EFI_INVALID_PARAMETER;
981 goto out;
982 }
983
984 efi_cin_empty_buffer();
985out:
986 return EFI_EXIT(ret);
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200987}
988
989/**
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200990 * efi_cin_read_key_stroke_ex() - read key stroke
991 *
992 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
993 * @key_data: key read from console
994 * Return: status code
995 *
996 * This function implements the ReadKeyStrokeEx service of the
997 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
998 *
999 * See the Unified Extensible Firmware Interface (UEFI) specification for
1000 * details.
1001 */
1002static efi_status_t EFIAPI efi_cin_read_key_stroke_ex(
1003 struct efi_simple_text_input_ex_protocol *this,
1004 struct efi_key_data *key_data)
1005{
1006 efi_status_t ret = EFI_SUCCESS;
1007
1008 EFI_ENTRY("%p, %p", this, key_data);
1009
1010 /* Check parameters */
1011 if (!this || !key_data) {
1012 ret = EFI_INVALID_PARAMETER;
1013 goto out;
1014 }
1015
1016 /* We don't do interrupts, so check for timers cooperatively */
1017 efi_timer_check();
1018
1019 /* Enable console input after ExitBootServices */
1020 efi_cin_check();
1021
1022 if (!key_available) {
Heinrich Schuchardtb6697c22022-09-01 23:30:09 +02001023 memset(key_data, 0, sizeof(struct efi_key_data));
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001024 ret = EFI_NOT_READY;
1025 goto out;
1026 }
Heinrich Schuchardt00b00a12019-04-06 20:59:24 +02001027 /*
1028 * CTRL+A - CTRL+Z have to be signaled as a - z.
1029 * SHIFT+CTRL+A - SHIFT+CTRL+Z have to be signaled as A - Z.
Heinrich Schuchardt068dc9c2022-09-02 00:49:12 +02001030 * CTRL+\ - CTRL+_ have to be signaled as \ - _.
Heinrich Schuchardt00b00a12019-04-06 20:59:24 +02001031 */
1032 switch (next_key.key.unicode_char) {
1033 case 0x01 ... 0x07:
1034 case 0x0b ... 0x0c:
1035 case 0x0e ... 0x1a:
1036 if (!(next_key.key_state.key_toggle_state &
1037 EFI_CAPS_LOCK_ACTIVE) ^
1038 !(next_key.key_state.key_shift_state &
1039 (EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED)))
1040 next_key.key.unicode_char += 0x40;
1041 else
1042 next_key.key.unicode_char += 0x60;
Heinrich Schuchardt068dc9c2022-09-02 00:49:12 +02001043 break;
1044 case 0x1c ... 0x1f:
1045 next_key.key.unicode_char += 0x40;
Heinrich Schuchardt00b00a12019-04-06 20:59:24 +02001046 }
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001047 *key_data = next_key;
1048 key_available = false;
1049 efi_con_in.wait_for_key->is_signaled = false;
Heinrich Schuchardt00b00a12019-04-06 20:59:24 +02001050
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001051out:
1052 return EFI_EXIT(ret);
1053}
1054
1055/**
1056 * efi_cin_set_state() - set toggle key state
1057 *
1058 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
Heinrich Schuchardta41ccf92019-05-18 17:07:52 +02001059 * @key_toggle_state: pointer to key toggle state
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001060 * Return: status code
1061 *
1062 * This function implements the SetState service of the
1063 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
1064 *
1065 * See the Unified Extensible Firmware Interface (UEFI) specification for
1066 * details.
1067 */
1068static efi_status_t EFIAPI efi_cin_set_state(
1069 struct efi_simple_text_input_ex_protocol *this,
Heinrich Schuchardta41ccf92019-05-18 17:07:52 +02001070 u8 *key_toggle_state)
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001071{
Heinrich Schuchardta41ccf92019-05-18 17:07:52 +02001072 EFI_ENTRY("%p, %p", this, key_toggle_state);
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001073 /*
1074 * U-Boot supports multiple console input sources like serial and
1075 * net console for which a key toggle state cannot be set at all.
1076 *
1077 * According to the UEFI specification it is allowable to not implement
1078 * this service.
1079 */
1080 return EFI_EXIT(EFI_UNSUPPORTED);
1081}
1082
1083/**
1084 * efi_cin_register_key_notify() - register key notification function
1085 *
1086 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
1087 * @key_data: key to be notified
1088 * @key_notify_function: function to be called if the key is pressed
1089 * @notify_handle: handle for unregistering the notification
1090 * Return: status code
1091 *
1092 * This function implements the SetState service of the
1093 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
1094 *
1095 * See the Unified Extensible Firmware Interface (UEFI) specification for
1096 * details.
1097 */
1098static efi_status_t EFIAPI efi_cin_register_key_notify(
1099 struct efi_simple_text_input_ex_protocol *this,
1100 struct efi_key_data *key_data,
1101 efi_status_t (EFIAPI *key_notify_function)(
1102 struct efi_key_data *key_data),
1103 void **notify_handle)
1104{
Heinrich Schuchardt695691e2018-09-11 22:38:12 +02001105 efi_status_t ret = EFI_SUCCESS;
1106 struct efi_cin_notify_function *notify_function;
1107
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001108 EFI_ENTRY("%p, %p, %p, %p",
1109 this, key_data, key_notify_function, notify_handle);
Heinrich Schuchardt695691e2018-09-11 22:38:12 +02001110
1111 /* Check parameters */
1112 if (!this || !key_data || !key_notify_function || !notify_handle) {
1113 ret = EFI_INVALID_PARAMETER;
1114 goto out;
1115 }
1116
1117 EFI_PRINT("u+%04x, sc %04x, sh %08x, tg %02x\n",
1118 key_data->key.unicode_char,
1119 key_data->key.scan_code,
1120 key_data->key_state.key_shift_state,
1121 key_data->key_state.key_toggle_state);
1122
1123 notify_function = calloc(1, sizeof(struct efi_cin_notify_function));
1124 if (!notify_function) {
1125 ret = EFI_OUT_OF_RESOURCES;
1126 goto out;
1127 }
1128 notify_function->key = *key_data;
1129 notify_function->function = key_notify_function;
1130 list_add_tail(&notify_function->link, &cin_notify_functions);
1131 *notify_handle = notify_function;
1132out:
1133 return EFI_EXIT(ret);
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001134}
1135
1136/**
1137 * efi_cin_unregister_key_notify() - unregister key notification function
1138 *
1139 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
1140 * @notification_handle: handle received when registering
1141 * Return: status code
1142 *
1143 * This function implements the SetState service of the
1144 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
1145 *
1146 * See the Unified Extensible Firmware Interface (UEFI) specification for
1147 * details.
1148 */
1149static efi_status_t EFIAPI efi_cin_unregister_key_notify(
1150 struct efi_simple_text_input_ex_protocol *this,
1151 void *notification_handle)
1152{
Heinrich Schuchardt695691e2018-09-11 22:38:12 +02001153 efi_status_t ret = EFI_INVALID_PARAMETER;
1154 struct efi_cin_notify_function *item, *notify_function =
1155 notification_handle;
1156
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001157 EFI_ENTRY("%p, %p", this, notification_handle);
Heinrich Schuchardt695691e2018-09-11 22:38:12 +02001158
1159 /* Check parameters */
1160 if (!this || !notification_handle)
1161 goto out;
1162
1163 list_for_each_entry(item, &cin_notify_functions, link) {
1164 if (item == notify_function) {
1165 ret = EFI_SUCCESS;
1166 break;
1167 }
1168 }
1169 if (ret != EFI_SUCCESS)
1170 goto out;
1171
1172 /* Remove the notify function */
1173 list_del(&notify_function->link);
1174 free(notify_function);
1175out:
1176 return EFI_EXIT(ret);
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001177}
1178
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001179/**
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001180 * efi_cin_reset() - drain the input buffer
1181 *
1182 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
1183 * @extended_verification: allow for exhaustive verification
1184 * Return: status code
1185 *
1186 * This function implements the Reset service of the
1187 * EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
1188 *
1189 * See the Unified Extensible Firmware Interface (UEFI) specification for
1190 * details.
1191 */
1192static efi_status_t EFIAPI efi_cin_reset
1193 (struct efi_simple_text_input_protocol *this,
1194 bool extended_verification)
1195{
1196 efi_status_t ret = EFI_SUCCESS;
1197
1198 EFI_ENTRY("%p, %d", this, extended_verification);
1199
1200 /* Check parameters */
1201 if (!this) {
1202 ret = EFI_INVALID_PARAMETER;
1203 goto out;
1204 }
1205
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001206 efi_cin_empty_buffer();
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001207out:
1208 return EFI_EXIT(ret);
1209}
1210
1211/**
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001212 * efi_cin_read_key_stroke() - read key stroke
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001213 *
1214 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
1215 * @key: key read from console
1216 * Return: status code
1217 *
1218 * This function implements the ReadKeyStroke service of the
1219 * EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
1220 *
1221 * See the Unified Extensible Firmware Interface (UEFI) specification for
1222 * details.
1223 */
1224static efi_status_t EFIAPI efi_cin_read_key_stroke
1225 (struct efi_simple_text_input_protocol *this,
1226 struct efi_input_key *key)
1227{
1228 efi_status_t ret = EFI_SUCCESS;
1229
1230 EFI_ENTRY("%p, %p", this, key);
1231
1232 /* Check parameters */
1233 if (!this || !key) {
1234 ret = EFI_INVALID_PARAMETER;
1235 goto out;
1236 }
1237
1238 /* We don't do interrupts, so check for timers cooperatively */
1239 efi_timer_check();
1240
1241 /* Enable console input after ExitBootServices */
1242 efi_cin_check();
1243
1244 if (!key_available) {
1245 ret = EFI_NOT_READY;
1246 goto out;
1247 }
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001248 *key = next_key.key;
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001249 key_available = false;
1250 efi_con_in.wait_for_key->is_signaled = false;
1251out:
1252 return EFI_EXIT(ret);
Alexander Graf4aacacc2016-03-04 01:10:00 +01001253}
1254
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001255static struct efi_simple_text_input_ex_protocol efi_con_in_ex = {
1256 .reset = efi_cin_reset_ex,
1257 .read_key_stroke_ex = efi_cin_read_key_stroke_ex,
1258 .wait_for_key_ex = NULL,
1259 .set_state = efi_cin_set_state,
1260 .register_key_notify = efi_cin_register_key_notify,
1261 .unregister_key_notify = efi_cin_unregister_key_notify,
1262};
1263
Heinrich Schuchardt3dabffd2018-09-08 10:20:10 +02001264struct efi_simple_text_input_protocol efi_con_in = {
Alexander Graf4aacacc2016-03-04 01:10:00 +01001265 .reset = efi_cin_reset,
1266 .read_key_stroke = efi_cin_read_key_stroke,
1267 .wait_for_key = NULL,
1268};
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001269
1270static struct efi_event *console_timer_event;
1271
Heinrich Schuchardtd8b878a2018-01-19 20:24:51 +01001272/*
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001273 * efi_console_timer_notify() - notify the console timer event
Heinrich Schuchardtd8b878a2018-01-19 20:24:51 +01001274 *
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001275 * @event: console timer event
1276 * @context: not used
Heinrich Schuchardtd8b878a2018-01-19 20:24:51 +01001277 */
xypron.glpk@gmx.de0ce42dc2017-07-20 05:26:07 +02001278static void EFIAPI efi_console_timer_notify(struct efi_event *event,
1279 void *context)
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001280{
1281 EFI_ENTRY("%p, %p", event, context);
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001282 efi_cin_check();
1283 EFI_EXIT(EFI_SUCCESS);
1284}
Heinrich Schuchardtd8b878a2018-01-19 20:24:51 +01001285
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001286/**
1287 * efi_key_notify() - notify the wait for key event
1288 *
1289 * @event: wait for key event
1290 * @context: not used
1291 */
1292static void EFIAPI efi_key_notify(struct efi_event *event, void *context)
1293{
1294 EFI_ENTRY("%p, %p", event, context);
1295 efi_cin_check();
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001296 EFI_EXIT(EFI_SUCCESS);
1297}
1298
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001299/**
1300 * efi_console_register() - install the console protocols
1301 *
1302 * This function is called from do_bootefi_exec().
Heinrich Schuchardta92e9ab2018-10-02 06:08:26 +02001303 *
1304 * Return: status code
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001305 */
Heinrich Schuchardta92e9ab2018-10-02 06:08:26 +02001306efi_status_t efi_console_register(void)
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001307{
1308 efi_status_t r;
Heinrich Schuchardt81244ea2022-02-04 20:47:09 +01001309 struct efi_device_path *dp;
Rob Clark49f7b4b2017-07-24 10:39:01 -04001310
Heinrich Schuchardt81244ea2022-02-04 20:47:09 +01001311 /* Install protocols on root node */
Ilias Apalodimas8ac0ebe2022-10-06 16:08:46 +03001312 r = efi_install_multiple_protocol_interfaces(&efi_root,
1313 &efi_guid_text_output_protocol,
1314 &efi_con_out,
1315 &efi_guid_text_input_protocol,
1316 &efi_con_in,
1317 &efi_guid_text_input_ex_protocol,
1318 &efi_con_in_ex,
1319 NULL);
Alexander Graf36bab912018-09-04 14:59:11 +02001320
Heinrich Schuchardt81244ea2022-02-04 20:47:09 +01001321 /* Create console node and install device path protocols */
1322 if (CONFIG_IS_ENABLED(DM_SERIAL)) {
1323 dp = efi_dp_from_uart();
1324 if (!dp)
1325 goto out_of_memory;
Alexander Graf36bab912018-09-04 14:59:11 +02001326
Heinrich Schuchardt81244ea2022-02-04 20:47:09 +01001327 /* Hook UART up to the device list */
1328 efi_add_handle(&uart_obj);
Alexander Graf36bab912018-09-04 14:59:11 +02001329
Heinrich Schuchardt81244ea2022-02-04 20:47:09 +01001330 /* Install device path */
1331 r = efi_add_protocol(&uart_obj, &efi_guid_device_path, dp);
1332 if (r != EFI_SUCCESS)
1333 goto out_of_memory;
1334 }
Rob Clark49f7b4b2017-07-24 10:39:01 -04001335
Heinrich Schuchardt580c13b2017-10-26 19:25:59 +02001336 /* Create console events */
Heinrich Schuchardtbf7f1692018-02-18 15:17:52 +01001337 r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK, efi_key_notify,
1338 NULL, NULL, &efi_con_in.wait_for_key);
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001339 if (r != EFI_SUCCESS) {
1340 printf("ERROR: Failed to register WaitForKey event\n");
1341 return r;
1342 }
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001343 efi_con_in_ex.wait_for_key_ex = efi_con_in.wait_for_key;
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001344 r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
Heinrich Schuchardtbf7f1692018-02-18 15:17:52 +01001345 efi_console_timer_notify, NULL, NULL,
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001346 &console_timer_event);
1347 if (r != EFI_SUCCESS) {
1348 printf("ERROR: Failed to register console event\n");
1349 return r;
1350 }
1351 /* 5000 ns cycle is sufficient for 2 MBaud */
1352 r = efi_set_timer(console_timer_event, EFI_TIMER_PERIODIC, 50);
1353 if (r != EFI_SUCCESS)
1354 printf("ERROR: Failed to set console timer\n");
1355 return r;
Heinrich Schuchardt580c13b2017-10-26 19:25:59 +02001356out_of_memory:
Heinrich Schuchardt6e8eff22018-09-08 19:57:24 +02001357 printf("ERROR: Out of memory\n");
Heinrich Schuchardt580c13b2017-10-26 19:25:59 +02001358 return r;
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001359}
Masahisa Kojimac5ff0a02022-09-12 17:33:50 +09001360
1361/**
1362 * efi_console_get_u16_string() - get user input string
1363 *
1364 * @cin: protocol interface to EFI_SIMPLE_TEXT_INPUT_PROTOCOL
1365 * @buf: buffer to store user input string in UTF16
1366 * @count: number of u16 string including NULL terminator that buf has
1367 * @filter_func: callback to filter user input
1368 * @row: row number to locate user input form
1369 * @col: column number to locate user input form
1370 * Return: status code
1371 */
1372efi_status_t efi_console_get_u16_string(struct efi_simple_text_input_protocol *cin,
1373 u16 *buf, efi_uintn_t count,
1374 efi_console_filter_func filter_func,
1375 int row, int col)
1376{
1377 efi_status_t ret;
1378 efi_uintn_t len = 0;
1379 struct efi_input_key key;
1380
1381 printf(ANSI_CURSOR_POSITION
1382 ANSI_CLEAR_LINE_TO_END
1383 ANSI_CURSOR_SHOW, row, col);
1384
Heinrich Schuchardt49dbcaf2022-10-15 12:22:37 +02001385 efi_cin_empty_buffer();
Masahisa Kojimac5ff0a02022-09-12 17:33:50 +09001386
1387 for (;;) {
1388 do {
1389 ret = EFI_CALL(cin->read_key_stroke(cin, &key));
1390 mdelay(10);
1391 } while (ret == EFI_NOT_READY);
1392
1393 if (key.unicode_char == u'\b') {
1394 if (len > 0)
1395 buf[--len] = u'\0';
1396
1397 printf(ANSI_CURSOR_POSITION
1398 "%ls"
1399 ANSI_CLEAR_LINE_TO_END, row, col, buf);
1400 continue;
1401 } else if (key.unicode_char == u'\r') {
1402 buf[len] = u'\0';
1403 return EFI_SUCCESS;
1404 } else if (key.unicode_char == 0x3 || key.scan_code == 23) {
1405 return EFI_ABORTED;
1406 } else if (key.unicode_char < 0x20) {
1407 /* ignore control codes other than Ctrl+C, '\r' and '\b' */
1408 continue;
1409 } else if (key.scan_code != 0) {
1410 /* only accept single ESC press for cancel */
1411 continue;
1412 }
1413
1414 if (filter_func) {
1415 if (filter_func(&key) != EFI_SUCCESS)
1416 continue;
1417 }
1418
1419 if (len >= (count - 1))
1420 continue;
1421
1422 buf[len] = key.unicode_char;
1423 len++;
1424 printf(ANSI_CURSOR_POSITION "%ls", row, col, buf);
1425 }
1426}