blob: 3164fd484e22b60a038d2c41e29ba768122b69db [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
Alexander Graf4aacacc2016-03-04 01:10:00 +010010#include <common.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
Matthias Brugger29c6f5f2019-03-05 12:50:18 +010079static int term_get_char(s32 *c)
80{
81 u64 timeout;
82
83 /* Wait up to 100 ms for a character */
84 timeout = timer_get_us() + 100000;
85
86 while (!tstc())
87 if (timer_get_us() > timeout)
88 return 1;
89
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +020090 *c = getchar();
Matthias Brugger29c6f5f2019-03-05 12:50:18 +010091 return 0;
92}
93
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +020094/**
Heinrich Schuchardt77135c22018-05-16 18:17:38 +020095 * Receive and parse a reply from the terminal.
96 *
97 * @n: array of return values
98 * @num: number of return values expected
99 * @end_char: character indicating end of terminal message
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200100 * Return: non-zero indicates error
Heinrich Schuchardt77135c22018-05-16 18:17:38 +0200101 */
102static int term_read_reply(int *n, int num, char end_char)
Alexander Graf4aacacc2016-03-04 01:10:00 +0100103{
Matthias Brugger29c6f5f2019-03-05 12:50:18 +0100104 s32 c;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100105 int i = 0;
106
Matthias Brugger29c6f5f2019-03-05 12:50:18 +0100107 if (term_get_char(&c) || c != cESC)
Alexander Graf4aacacc2016-03-04 01:10:00 +0100108 return -1;
Matthias Brugger29c6f5f2019-03-05 12:50:18 +0100109
110 if (term_get_char(&c) || c != '[')
Alexander Graf4aacacc2016-03-04 01:10:00 +0100111 return -1;
112
113 n[0] = 0;
114 while (1) {
Matthias Brugger29c6f5f2019-03-05 12:50:18 +0100115 if (!term_get_char(&c)) {
116 if (c == ';') {
117 i++;
118 if (i >= num)
119 return -1;
120 n[i] = 0;
121 continue;
122 } else if (c == end_char) {
123 break;
124 } else if (c > '9' || c < '0') {
Alexander Graf4aacacc2016-03-04 01:10:00 +0100125 return -1;
Matthias Brugger29c6f5f2019-03-05 12:50:18 +0100126 }
127
128 /* Read one more decimal position */
129 n[i] *= 10;
130 n[i] += c - '0';
131 } else {
Alexander Graf4aacacc2016-03-04 01:10:00 +0100132 return -1;
133 }
Alexander Graf4aacacc2016-03-04 01:10:00 +0100134 }
Heinrich Schuchardt77135c22018-05-16 18:17:38 +0200135 if (i != num - 1)
136 return -1;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100137
138 return 0;
139}
140
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200141/**
142 * efi_cout_output_string() - write Unicode string to console
143 *
144 * This function implements the OutputString service of the simple text output
145 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
146 * for details.
147 *
148 * @this: simple text output protocol
149 * @string: u16 string
150 * Return: status code
151 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100152static efi_status_t EFIAPI efi_cout_output_string(
153 struct efi_simple_text_output_protocol *this,
Heinrich Schuchardt84494282021-01-05 07:50:09 +0100154 const u16 *string)
Alexander Graf4aacacc2016-03-04 01:10:00 +0100155{
Rob Clark1ef185d2017-09-13 18:05:44 -0400156 struct simple_text_output_mode *con = &efi_con_mode;
157 struct cout_mode *mode = &efi_cout_modes[con->mode];
Heinrich Schuchardta419d1d2018-08-31 21:31:32 +0200158 char *buf, *pos;
Heinrich Schuchardt84494282021-01-05 07:50:09 +0100159 const u16 *p;
Heinrich Schuchardta419d1d2018-08-31 21:31:32 +0200160 efi_status_t ret = EFI_SUCCESS;
Rob Clark1ef185d2017-09-13 18:05:44 -0400161
Heinrich Schuchardta419d1d2018-08-31 21:31:32 +0200162 EFI_ENTRY("%p, %p", this, string);
Rob Clark1ef185d2017-09-13 18:05:44 -0400163
Heinrich Schuchardte60b2982019-05-18 18:11:54 +0200164 if (!this || !string) {
165 ret = EFI_INVALID_PARAMETER;
166 goto out;
167 }
168
Heinrich Schuchardta419d1d2018-08-31 21:31:32 +0200169 buf = malloc(utf16_utf8_strlen(string) + 1);
170 if (!buf) {
171 ret = EFI_OUT_OF_RESOURCES;
172 goto out;
173 }
174 pos = buf;
175 utf16_utf8_strcpy(&pos, string);
Rob Clark1ef185d2017-09-13 18:05:44 -0400176 fputs(stdout, buf);
Heinrich Schuchardta419d1d2018-08-31 21:31:32 +0200177 free(buf);
Rob Clark1ef185d2017-09-13 18:05:44 -0400178
Heinrich Schuchardt8aaeed92018-04-29 16:24:25 +0200179 /*
180 * Update the cursor position.
181 *
182 * The UEFI spec provides advance rules for U+0000, U+0008, U+000A,
Heinrich Schuchardtda88da82019-09-04 21:13:45 +0200183 * and U000D. All other control characters are ignored. Any non-control
184 * character increase the column by one.
Heinrich Schuchardt8aaeed92018-04-29 16:24:25 +0200185 */
186 for (p = string; *p; ++p) {
Rob Clark1ef185d2017-09-13 18:05:44 -0400187 switch (*p) {
Heinrich Schuchardt8aaeed92018-04-29 16:24:25 +0200188 case '\b': /* U+0008, backspace */
Heinrich Schuchardtda88da82019-09-04 21:13:45 +0200189 if (con->cursor_column)
190 con->cursor_column--;
Rob Clark1ef185d2017-09-13 18:05:44 -0400191 break;
Heinrich Schuchardt8aaeed92018-04-29 16:24:25 +0200192 case '\n': /* U+000A, newline */
Rob Clark1ef185d2017-09-13 18:05:44 -0400193 con->cursor_column = 0;
194 con->cursor_row++;
195 break;
Heinrich Schuchardt8aaeed92018-04-29 16:24:25 +0200196 case '\r': /* U+000D, carriage-return */
197 con->cursor_column = 0;
Rob Clark1ef185d2017-09-13 18:05:44 -0400198 break;
Heinrich Schuchardt8aaeed92018-04-29 16:24:25 +0200199 case 0xd800 ... 0xdbff:
200 /*
201 * Ignore high surrogates, we do not want to count a
202 * Unicode character twice.
203 */
Rob Clark1ef185d2017-09-13 18:05:44 -0400204 break;
205 default:
Heinrich Schuchardtda88da82019-09-04 21:13:45 +0200206 /* Exclude control codes */
207 if (*p > 0x1f)
208 con->cursor_column++;
Rob Clark1ef185d2017-09-13 18:05:44 -0400209 break;
210 }
211 if (con->cursor_column >= mode->columns) {
212 con->cursor_column = 0;
213 con->cursor_row++;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100214 }
Heinrich Schuchardtda88da82019-09-04 21:13:45 +0200215 /*
216 * When we exceed the row count the terminal will scroll up one
217 * line. We have to adjust the cursor position.
218 */
219 if (con->cursor_row >= mode->rows && con->cursor_row)
220 con->cursor_row--;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100221 }
222
Heinrich Schuchardta419d1d2018-08-31 21:31:32 +0200223out:
224 return EFI_EXIT(ret);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100225}
226
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200227/**
228 * efi_cout_test_string() - test writing Unicode string to console
229 *
230 * This function implements the TestString service of the simple text output
231 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
232 * for details.
233 *
234 * As in OutputString we simply convert UTF-16 to UTF-8 there are no unsupported
235 * code points and we can always return EFI_SUCCESS.
236 *
237 * @this: simple text output protocol
238 * @string: u16 string
239 * Return: status code
240 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100241static efi_status_t EFIAPI efi_cout_test_string(
242 struct efi_simple_text_output_protocol *this,
Heinrich Schuchardt84494282021-01-05 07:50:09 +0100243 const u16 *string)
Alexander Graf4aacacc2016-03-04 01:10:00 +0100244{
245 EFI_ENTRY("%p, %p", this, string);
246 return EFI_EXIT(EFI_SUCCESS);
247}
248
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200249/**
250 * cout_mode_matches() - check if mode has given terminal size
251 *
252 * @mode: text mode
253 * @rows: number of rows
254 * @cols: number of columns
255 * Return: true if number of rows and columns matches the mode and
256 * the mode is present
257 */
Emmanuel Vadota074d5d2016-11-08 06:03:29 +0100258static bool cout_mode_matches(struct cout_mode *mode, int rows, int cols)
259{
260 if (!mode->present)
261 return false;
262
263 return (mode->rows == rows) && (mode->columns == cols);
264}
265
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200266/**
Heinrich Schuchardtae165ef2021-03-16 12:56:57 +0100267 * query_console_serial() - query serial console size
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200268 *
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200269 * When using a serial console or the net console we can only devise the
270 * terminal size by querying the terminal using ECMA-48 control sequences.
271 *
Heinrich Schuchardtdc305ad2019-09-05 20:37:13 +0200272 * @rows: pointer to return number of rows
273 * @cols: pointer to return number of columns
274 * Returns: 0 on success
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200275 */
Rob Clark1e948922017-09-13 18:05:42 -0400276static int query_console_serial(int *rows, int *cols)
277{
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200278 int ret = 0;
279 int n[2];
Rob Clark1e948922017-09-13 18:05:42 -0400280
281 /* Empty input buffer */
282 while (tstc())
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200283 getchar();
Rob Clark1e948922017-09-13 18:05:42 -0400284
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200285 /*
286 * Not all terminals understand CSI [18t for querying the console size.
287 * We should adhere to escape sequences documented in the console_codes
Heinrich Schuchardt5e96f422018-10-18 21:51:38 +0200288 * man page and the ECMA-48 standard.
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200289 *
290 * So here we follow a different approach. We position the cursor to the
291 * bottom right and query its position. Before leaving the function we
292 * restore the original cursor position.
293 */
294 printf(ESC "7" /* Save cursor position */
295 ESC "[r" /* Set scrolling region to full window */
296 ESC "[999;999H" /* Move to bottom right corner */
297 ESC "[6n"); /* Query cursor position */
Rob Clark1e948922017-09-13 18:05:42 -0400298
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200299 /* Read {rows,cols} */
300 if (term_read_reply(n, 2, 'R')) {
301 ret = 1;
302 goto out;
303 }
Rob Clark1e948922017-09-13 18:05:42 -0400304
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200305 *cols = n[1];
306 *rows = n[0];
307out:
308 printf(ESC "8"); /* Restore cursor position */
309 return ret;
Rob Clark1e948922017-09-13 18:05:42 -0400310}
311
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200312/**
Heinrich Schuchardtae165ef2021-03-16 12:56:57 +0100313 * query_vidconsole() - query video console size
314 *
315 *
316 * @rows: pointer to return number of rows
317 * @cols: pointer to return number of columns
318 * Returns: 0 on success
319 */
320static int __maybe_unused query_vidconsole(int *rows, int *cols)
321{
322 const char *stdout_name = env_get("stdout");
323 struct stdio_dev *stdout_dev;
324 struct udevice *dev;
325 struct vidconsole_priv *priv;
326
327 if (!stdout_name || strncmp(stdout_name, "vidconsole", 10))
328 return -ENODEV;
329 stdout_dev = stdio_get_by_name("vidconsole");
330 if (!stdout_dev)
331 return -ENODEV;
332 dev = stdout_dev->priv;
333 if (!dev)
334 return -ENODEV;
335 priv = dev_get_uclass_priv(dev);
336 if (!priv)
337 return -ENODEV;
338 *rows = priv->rows;
339 *cols = priv->cols;
340 return 0;
341}
342
343/**
Heinrich Schuchardt761908e2022-06-14 08:02:03 +0200344 * efi_setup_console_size() - update the mode table.
Heinrich Schuchardt75b4e692018-04-29 20:02:46 +0200345 *
346 * By default the only mode available is 80x25. If the console has at least 50
347 * lines, enable mode 80x50. If we can query the console size and it is neither
348 * 80x25 nor 80x50, set it as an additional mode.
349 */
Heinrich Schuchardt761908e2022-06-14 08:02:03 +0200350void efi_setup_console_size(void)
Heinrich Schuchardt75b4e692018-04-29 20:02:46 +0200351{
Alexander Graf28795322018-06-03 15:51:17 +0200352 int rows = 25, cols = 80;
Heinrich Schuchardtae165ef2021-03-16 12:56:57 +0100353 int ret = -ENODEV;
Heinrich Schuchardt75b4e692018-04-29 20:02:46 +0200354
Heinrich Schuchardtc86d2bb2021-06-29 10:09:14 +0200355 if (IS_ENABLED(CONFIG_DM_VIDEO))
Heinrich Schuchardtae165ef2021-03-16 12:56:57 +0100356 ret = query_vidconsole(&rows, &cols);
357 if (ret)
358 ret = query_console_serial(&rows, &cols);
359 if (ret)
Heinrich Schuchardt75b4e692018-04-29 20:02:46 +0200360 return;
Heinrich Schuchardt75b4e692018-04-29 20:02:46 +0200361
Heinrich Schuchardt761908e2022-06-14 08:02:03 +0200362 log_debug("Console size %dx%d\n", rows, cols);
363
Heinrich Schuchardt75b4e692018-04-29 20:02:46 +0200364 /* Test if we can have Mode 1 */
365 if (cols >= 80 && rows >= 50) {
366 efi_cout_modes[1].present = 1;
367 efi_con_mode.max_mode = 2;
368 }
369
370 /*
371 * Install our mode as mode 2 if it is different
372 * than mode 0 or 1 and set it as the currently selected mode
373 */
374 if (!cout_mode_matches(&efi_cout_modes[0], rows, cols) &&
375 !cout_mode_matches(&efi_cout_modes[1], rows, cols)) {
376 efi_cout_modes[EFI_COUT_MODE_2].columns = cols;
377 efi_cout_modes[EFI_COUT_MODE_2].rows = rows;
378 efi_cout_modes[EFI_COUT_MODE_2].present = 1;
379 efi_con_mode.max_mode = EFI_MAX_COUT_MODE;
380 efi_con_mode.mode = EFI_COUT_MODE_2;
381 }
382}
383
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200384/**
385 * efi_cout_query_mode() - get terminal size for a text mode
386 *
387 * This function implements the QueryMode service of the simple text output
388 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
389 * for details.
390 *
391 * @this: simple text output protocol
392 * @mode_number: mode number to retrieve information on
393 * @columns: number of columns
394 * @rows: number of rows
395 * Return: status code
396 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100397static efi_status_t EFIAPI efi_cout_query_mode(
398 struct efi_simple_text_output_protocol *this,
399 unsigned long mode_number, unsigned long *columns,
400 unsigned long *rows)
401{
402 EFI_ENTRY("%p, %ld, %p, %p", this, mode_number, columns, rows);
403
Emmanuel Vadota074d5d2016-11-08 06:03:29 +0100404 if (mode_number >= efi_con_mode.max_mode)
405 return EFI_EXIT(EFI_UNSUPPORTED);
406
407 if (efi_cout_modes[mode_number].present != 1)
408 return EFI_EXIT(EFI_UNSUPPORTED);
409
Alexander Graf4aacacc2016-03-04 01:10:00 +0100410 if (columns)
Emmanuel Vadota074d5d2016-11-08 06:03:29 +0100411 *columns = efi_cout_modes[mode_number].columns;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100412 if (rows)
Emmanuel Vadota074d5d2016-11-08 06:03:29 +0100413 *rows = efi_cout_modes[mode_number].rows;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100414
415 return EFI_EXIT(EFI_SUCCESS);
416}
417
Rob Clark87ef0012017-10-10 08:23:01 -0400418static const struct {
419 unsigned int fg;
420 unsigned int bg;
421} color[] = {
422 { 30, 40 }, /* 0: black */
423 { 34, 44 }, /* 1: blue */
424 { 32, 42 }, /* 2: green */
425 { 36, 46 }, /* 3: cyan */
426 { 31, 41 }, /* 4: red */
427 { 35, 45 }, /* 5: magenta */
Heinrich Schuchardt6e8eff22018-09-08 19:57:24 +0200428 { 33, 43 }, /* 6: brown, map to yellow as EDK2 does*/
429 { 37, 47 }, /* 7: light gray, map to white */
Rob Clark87ef0012017-10-10 08:23:01 -0400430};
431
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200432/**
433 * efi_cout_set_attribute() - set fore- and background color
434 *
435 * This function implements the SetAttribute service of the simple text output
436 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
437 * for details.
438 *
439 * @this: simple text output protocol
440 * @attribute: foreground color - bits 0-3, background color - bits 4-6
441 * Return: status code
442 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100443static efi_status_t EFIAPI efi_cout_set_attribute(
444 struct efi_simple_text_output_protocol *this,
445 unsigned long attribute)
446{
Rob Clark87ef0012017-10-10 08:23:01 -0400447 unsigned int bold = EFI_ATTR_BOLD(attribute);
448 unsigned int fg = EFI_ATTR_FG(attribute);
449 unsigned int bg = EFI_ATTR_BG(attribute);
450
Alexander Graf4aacacc2016-03-04 01:10:00 +0100451 EFI_ENTRY("%p, %lx", this, attribute);
452
Heinrich Schuchardt1e129622019-06-14 07:16:57 +0200453 efi_con_mode.attribute = attribute;
Rob Clark87ef0012017-10-10 08:23:01 -0400454 if (attribute)
455 printf(ESC"[%u;%u;%um", bold, color[fg].fg, color[bg].bg);
456 else
457 printf(ESC"[0;37;40m");
458
459 return EFI_EXIT(EFI_SUCCESS);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100460}
461
Heinrich Schuchardt7995cbe2019-12-22 07:15:55 +0000462/**
463 * efi_cout_clear_screen() - clear screen
464 *
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200465 * This function implements the ClearScreen service of the simple text output
466 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
467 * for details.
Heinrich Schuchardt7995cbe2019-12-22 07:15:55 +0000468 *
469 * @this: pointer to the protocol instance
470 * Return: status code
471 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100472static efi_status_t EFIAPI efi_cout_clear_screen(
473 struct efi_simple_text_output_protocol *this)
474{
475 EFI_ENTRY("%p", this);
476
Heinrich Schuchardt7995cbe2019-12-22 07:15:55 +0000477 /*
478 * The Linux console wants both a clear and a home command. The video
479 * uclass does not support <ESC>[H without coordinates, yet.
480 */
481 printf(ESC "[2J" ESC "[1;1H");
Heinrich Schuchardt2d099322018-07-05 08:18:00 +0200482 efi_con_mode.cursor_column = 0;
483 efi_con_mode.cursor_row = 0;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100484
485 return EFI_EXIT(EFI_SUCCESS);
486}
487
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200488/**
489 * efi_cout_clear_set_mode() - set text model
490 *
491 * This function implements the SetMode service of the simple text output
492 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
493 * for details.
494 *
495 * @this: pointer to the protocol instance
496 * @mode_number: number of the text mode to set
497 * Return: status code
498 */
Heinrich Schuchardt757cc4a2019-06-14 07:20:51 +0200499static efi_status_t EFIAPI efi_cout_set_mode(
500 struct efi_simple_text_output_protocol *this,
501 unsigned long mode_number)
502{
503 EFI_ENTRY("%p, %ld", this, mode_number);
504
505 if (mode_number >= efi_con_mode.max_mode)
506 return EFI_EXIT(EFI_UNSUPPORTED);
Heinrich Schuchardt6a6afa72019-09-04 22:46:13 +0200507
508 if (!efi_cout_modes[mode_number].present)
509 return EFI_EXIT(EFI_UNSUPPORTED);
510
Heinrich Schuchardt757cc4a2019-06-14 07:20:51 +0200511 efi_con_mode.mode = mode_number;
512 EFI_CALL(efi_cout_clear_screen(this));
513
514 return EFI_EXIT(EFI_SUCCESS);
515}
516
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200517/**
518 * efi_cout_reset() - reset the terminal
519 *
520 * This function implements the Reset service of the simple text output
521 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
522 * for details.
523 *
524 * @this: pointer to the protocol instance
525 * @extended_verification: if set an extended verification may be executed
526 * Return: status code
527 */
Heinrich Schuchardt09866c22018-07-05 19:58:07 +0200528static efi_status_t EFIAPI efi_cout_reset(
529 struct efi_simple_text_output_protocol *this,
530 char extended_verification)
531{
532 EFI_ENTRY("%p, %d", this, extended_verification);
533
Heinrich Schuchardt09866c22018-07-05 19:58:07 +0200534 /* Set default colors */
Heinrich Schuchardt1e129622019-06-14 07:16:57 +0200535 efi_con_mode.attribute = 0x07;
Heinrich Schuchardt09866c22018-07-05 19:58:07 +0200536 printf(ESC "[0;37;40m");
Heinrich Schuchardt30c9d672022-04-30 09:05:04 +0200537 /* Clear screen */
538 EFI_CALL(efi_cout_clear_screen(this));
Heinrich Schuchardt09866c22018-07-05 19:58:07 +0200539
540 return EFI_EXIT(EFI_SUCCESS);
541}
542
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200543/**
544 * efi_cout_set_cursor_position() - reset the terminal
545 *
546 * This function implements the SetCursorPosition service of the simple text
547 * output protocol. See the Unified Extensible Firmware Interface (UEFI)
548 * specification for details.
549 *
550 * @this: pointer to the protocol instance
551 * @column: column to move to
552 * @row: row to move to
553 * Return: status code
554 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100555static efi_status_t EFIAPI efi_cout_set_cursor_position(
556 struct efi_simple_text_output_protocol *this,
557 unsigned long column, unsigned long row)
558{
Heinrich Schuchardtdcac1d92018-09-14 18:49:26 +0200559 efi_status_t ret = EFI_SUCCESS;
560 struct simple_text_output_mode *con = &efi_con_mode;
561 struct cout_mode *mode = &efi_cout_modes[con->mode];
562
Alexander Graf4aacacc2016-03-04 01:10:00 +0100563 EFI_ENTRY("%p, %ld, %ld", this, column, row);
564
Heinrich Schuchardtdcac1d92018-09-14 18:49:26 +0200565 /* Check parameters */
566 if (!this) {
567 ret = EFI_INVALID_PARAMETER;
568 goto out;
569 }
570 if (row >= mode->rows || column >= mode->columns) {
571 ret = EFI_UNSUPPORTED;
572 goto out;
573 }
574
575 /*
576 * Set cursor position by sending CSI H.
577 * EFI origin is [0, 0], terminal origin is [1, 1].
578 */
579 printf(ESC "[%d;%dH", (int)row + 1, (int)column + 1);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100580 efi_con_mode.cursor_column = column;
581 efi_con_mode.cursor_row = row;
Heinrich Schuchardtdcac1d92018-09-14 18:49:26 +0200582out:
583 return EFI_EXIT(ret);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100584}
585
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200586/**
587 * efi_cout_enable_cursor() - enable the cursor
588 *
589 * This function implements the EnableCursor service of the simple text output
590 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
591 * for details.
592 *
593 * @this: pointer to the protocol instance
594 * @enable: if true enable, if false disable the cursor
595 * Return: status code
596 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100597static efi_status_t EFIAPI efi_cout_enable_cursor(
598 struct efi_simple_text_output_protocol *this,
599 bool enable)
600{
601 EFI_ENTRY("%p, %d", this, enable);
602
603 printf(ESC"[?25%c", enable ? 'h' : 'l');
Heinrich Schuchardt53f26b92019-06-02 22:54:28 +0200604 efi_con_mode.cursor_visible = !!enable;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100605
606 return EFI_EXIT(EFI_SUCCESS);
607}
608
Heinrich Schuchardt580c13b2017-10-26 19:25:59 +0200609struct efi_simple_text_output_protocol efi_con_out = {
Alexander Graf4aacacc2016-03-04 01:10:00 +0100610 .reset = efi_cout_reset,
611 .output_string = efi_cout_output_string,
612 .test_string = efi_cout_test_string,
613 .query_mode = efi_cout_query_mode,
614 .set_mode = efi_cout_set_mode,
615 .set_attribute = efi_cout_set_attribute,
616 .clear_screen = efi_cout_clear_screen,
617 .set_cursor_position = efi_cout_set_cursor_position,
618 .enable_cursor = efi_cout_enable_cursor,
619 .mode = (void*)&efi_con_mode,
620};
621
Heinrich Schuchardt695691e2018-09-11 22:38:12 +0200622/**
623 * struct efi_cin_notify_function - registered console input notify function
624 *
625 * @link: link to list
Heinrich Schuchardtdc305ad2019-09-05 20:37:13 +0200626 * @key: key to notify
Heinrich Schuchardt695691e2018-09-11 22:38:12 +0200627 * @function: function to call
628 */
629struct efi_cin_notify_function {
630 struct list_head link;
631 struct efi_key_data key;
632 efi_status_t (EFIAPI *function)
633 (struct efi_key_data *key_data);
634};
635
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200636static bool key_available;
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200637static struct efi_key_data next_key;
Heinrich Schuchardt695691e2018-09-11 22:38:12 +0200638static LIST_HEAD(cin_notify_functions);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100639
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200640/**
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200641 * set_shift_mask() - set shift mask
642 *
643 * @mod: Xterm shift mask
Heinrich Schuchardtdc305ad2019-09-05 20:37:13 +0200644 * @key_state: receives the state of the shift, alt, control, and logo keys
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200645 */
646void set_shift_mask(int mod, struct efi_key_state *key_state)
647{
648 key_state->key_shift_state = EFI_SHIFT_STATE_VALID;
649 if (mod) {
650 --mod;
651 if (mod & 1)
652 key_state->key_shift_state |= EFI_LEFT_SHIFT_PRESSED;
653 if (mod & 2)
654 key_state->key_shift_state |= EFI_LEFT_ALT_PRESSED;
655 if (mod & 4)
656 key_state->key_shift_state |= EFI_LEFT_CONTROL_PRESSED;
Heinrich Schuchardtfea93d62019-06-16 22:33:20 +0200657 if (!mod || (mod & 8))
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200658 key_state->key_shift_state |= EFI_LEFT_LOGO_PRESSED;
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200659 }
660}
661
662/**
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200663 * analyze_modifiers() - analyze modifiers (shift, alt, ctrl) for function keys
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200664 *
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100665 * This gets called when we have already parsed CSI.
666 *
Heinrich Schuchardtdc305ad2019-09-05 20:37:13 +0200667 * @key_state: receives the state of the shift, alt, control, and logo keys
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200668 * Return: the unmodified code
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100669 */
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200670static int analyze_modifiers(struct efi_key_state *key_state)
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100671{
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200672 int c, mod = 0, ret = 0;
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100673
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200674 c = getchar();
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100675
676 if (c != ';') {
677 ret = c;
678 if (c == '~')
679 goto out;
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200680 c = getchar();
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100681 }
682 for (;;) {
683 switch (c) {
684 case '0'...'9':
685 mod *= 10;
686 mod += c - '0';
687 /* fall through */
688 case ';':
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200689 c = getchar();
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100690 break;
691 default:
692 goto out;
693 }
694 }
695out:
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200696 set_shift_mask(mod, key_state);
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100697 if (!ret)
698 ret = c;
699 return ret;
700}
701
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200702/**
703 * efi_cin_read_key() - read a key from the console input
704 *
705 * @key: - key received
706 * Return: - status code
707 */
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200708static efi_status_t efi_cin_read_key(struct efi_key_data *key)
Alexander Graf4aacacc2016-03-04 01:10:00 +0100709{
710 struct efi_input_key pressed_key = {
711 .scan_code = 0,
712 .unicode_char = 0,
713 };
Heinrich Schuchardtfc5f1a12018-09-12 00:05:32 +0200714 s32 ch;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100715
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200716 if (console_read_unicode(&ch))
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200717 return EFI_NOT_READY;
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200718
719 key->key_state.key_shift_state = EFI_SHIFT_STATE_INVALID;
720 key->key_state.key_toggle_state = EFI_TOGGLE_STATE_INVALID;
721
Heinrich Schuchardtfc5f1a12018-09-12 00:05:32 +0200722 /* We do not support multi-word codes */
723 if (ch >= 0x10000)
724 ch = '?';
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200725
726 switch (ch) {
727 case 0x1b:
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100728 /*
Heinrich Schuchardte5c93172020-12-27 14:47:50 +0100729 * If a second key is received within 10 ms, assume that we are
730 * dealing with an escape sequence. Otherwise consider this the
731 * escape key being hit. 10 ms is long enough to work fine at
732 * 1200 baud and above.
733 */
734 udelay(10000);
735 if (!tstc()) {
736 pressed_key.scan_code = 23;
737 break;
738 }
739 /*
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100740 * Xterm Control Sequences
741 * https://www.xfree86.org/4.8.0/ctlseqs.html
742 */
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200743 ch = getchar();
Alexander Graf4aacacc2016-03-04 01:10:00 +0100744 switch (ch) {
745 case cESC: /* ESC */
746 pressed_key.scan_code = 23;
747 break;
Heinrich Schuchardt46e41d02019-06-16 21:41:13 +0200748 case 'O': /* F1 - F4, End */
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200749 ch = getchar();
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200750 /* consider modifiers */
Heinrich Schuchardt46e41d02019-06-16 21:41:13 +0200751 if (ch == 'F') { /* End */
752 pressed_key.scan_code = 6;
753 break;
754 } else if (ch < 'P') {
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200755 set_shift_mask(ch - '0', &key->key_state);
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200756 ch = getchar();
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200757 }
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100758 pressed_key.scan_code = ch - 'P' + 11;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100759 break;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100760 case '[':
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200761 ch = getchar();
Alexander Graf4aacacc2016-03-04 01:10:00 +0100762 switch (ch) {
763 case 'A'...'D': /* up, down right, left */
764 pressed_key.scan_code = ch - 'A' + 1;
765 break;
766 case 'F': /* End */
767 pressed_key.scan_code = 6;
768 break;
769 case 'H': /* Home */
770 pressed_key.scan_code = 5;
771 break;
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100772 case '1':
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200773 ch = analyze_modifiers(&key->key_state);
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100774 switch (ch) {
775 case '1'...'5': /* F1 - F5 */
776 pressed_key.scan_code = ch - '1' + 11;
777 break;
Heinrich Schuchardt46e41d02019-06-16 21:41:13 +0200778 case '6'...'9': /* F5 - F8 */
779 pressed_key.scan_code = ch - '6' + 15;
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100780 break;
781 case 'A'...'D': /* up, down right, left */
782 pressed_key.scan_code = ch - 'A' + 1;
783 break;
Heinrich Schuchardt46e41d02019-06-16 21:41:13 +0200784 case 'F': /* End */
785 pressed_key.scan_code = 6;
786 break;
787 case 'H': /* Home */
788 pressed_key.scan_code = 5;
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100789 break;
Heinrich Schuchardt46e41d02019-06-16 21:41:13 +0200790 case '~': /* Home */
791 pressed_key.scan_code = 5;
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100792 break;
793 }
Alexander Graf4aacacc2016-03-04 01:10:00 +0100794 break;
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100795 case '2':
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200796 ch = analyze_modifiers(&key->key_state);
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100797 switch (ch) {
798 case '0'...'1': /* F9 - F10 */
799 pressed_key.scan_code = ch - '0' + 19;
800 break;
801 case '3'...'4': /* F11 - F12 */
802 pressed_key.scan_code = ch - '3' + 21;
803 break;
804 case '~': /* INS */
805 pressed_key.scan_code = 7;
806 break;
807 }
Alexander Graf4aacacc2016-03-04 01:10:00 +0100808 break;
809 case '3': /* DEL */
810 pressed_key.scan_code = 8;
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200811 analyze_modifiers(&key->key_state);
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100812 break;
813 case '5': /* PG UP */
814 pressed_key.scan_code = 9;
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200815 analyze_modifiers(&key->key_state);
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100816 break;
817 case '6': /* PG DOWN */
818 pressed_key.scan_code = 10;
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200819 analyze_modifiers(&key->key_state);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100820 break;
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200821 } /* [ */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100822 break;
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200823 default:
824 /* ALT key */
825 set_shift_mask(3, &key->key_state);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100826 }
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200827 break;
828 case 0x7f:
Alexander Graf4aacacc2016-03-04 01:10:00 +0100829 /* Backspace */
830 ch = 0x08;
831 }
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200832 if (pressed_key.scan_code) {
833 key->key_state.key_shift_state |= EFI_SHIFT_STATE_VALID;
834 } else {
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100835 pressed_key.unicode_char = ch;
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200836
837 /*
838 * Assume left control key for control characters typically
839 * entered using the control key.
840 */
841 if (ch >= 0x01 && ch <= 0x1f) {
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200842 key->key_state.key_shift_state |=
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200843 EFI_SHIFT_STATE_VALID;
844 switch (ch) {
845 case 0x01 ... 0x07:
846 case 0x0b ... 0x0c:
847 case 0x0e ... 0x1f:
848 key->key_state.key_shift_state |=
849 EFI_LEFT_CONTROL_PRESSED;
850 }
851 }
852 }
853 key->key = pressed_key;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100854
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200855 return EFI_SUCCESS;
856}
857
858/**
Heinrich Schuchardt695691e2018-09-11 22:38:12 +0200859 * efi_cin_notify() - notify registered functions
860 */
861static void efi_cin_notify(void)
862{
863 struct efi_cin_notify_function *item;
864
865 list_for_each_entry(item, &cin_notify_functions, link) {
866 bool match = true;
867
868 /* We do not support toggle states */
869 if (item->key.key.unicode_char || item->key.key.scan_code) {
870 if (item->key.key.unicode_char !=
871 next_key.key.unicode_char ||
872 item->key.key.scan_code != next_key.key.scan_code)
873 match = false;
874 }
875 if (item->key.key_state.key_shift_state &&
876 item->key.key_state.key_shift_state !=
877 next_key.key_state.key_shift_state)
878 match = false;
879
880 if (match)
881 /* We don't bother about the return code */
882 EFI_CALL(item->function(&next_key));
883 }
884}
885
886/**
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200887 * efi_cin_check() - check if keyboard input is available
888 */
889static void efi_cin_check(void)
890{
891 efi_status_t ret;
892
893 if (key_available) {
Heinrich Schuchardt7b4b8d862019-06-07 06:47:01 +0200894 efi_signal_event(efi_con_in.wait_for_key);
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200895 return;
896 }
897
898 if (tstc()) {
899 ret = efi_cin_read_key(&next_key);
900 if (ret == EFI_SUCCESS) {
901 key_available = true;
902
Heinrich Schuchardt695691e2018-09-11 22:38:12 +0200903 /* Notify registered functions */
904 efi_cin_notify();
905
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200906 /* Queue the wait for key event */
Heinrich Schuchardt695691e2018-09-11 22:38:12 +0200907 if (key_available)
Heinrich Schuchardt7b4b8d862019-06-07 06:47:01 +0200908 efi_signal_event(efi_con_in.wait_for_key);
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200909 }
910 }
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200911}
912
913/**
914 * efi_cin_empty_buffer() - empty input buffer
915 */
916static void efi_cin_empty_buffer(void)
917{
918 while (tstc())
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200919 getchar();
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200920 key_available = false;
921}
922
923/**
924 * efi_cin_reset_ex() - reset console input
925 *
926 * @this: - the extended simple text input protocol
927 * @extended_verification: - extended verification
928 *
929 * This function implements the reset service of the
930 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
931 *
932 * See the Unified Extensible Firmware Interface (UEFI) specification for
933 * details.
934 *
935 * Return: old value of the task priority level
936 */
937static efi_status_t EFIAPI efi_cin_reset_ex(
938 struct efi_simple_text_input_ex_protocol *this,
939 bool extended_verification)
940{
941 efi_status_t ret = EFI_SUCCESS;
942
943 EFI_ENTRY("%p, %d", this, extended_verification);
944
945 /* Check parameters */
946 if (!this) {
947 ret = EFI_INVALID_PARAMETER;
948 goto out;
949 }
950
951 efi_cin_empty_buffer();
952out:
953 return EFI_EXIT(ret);
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200954}
955
956/**
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200957 * efi_cin_read_key_stroke_ex() - read key stroke
958 *
959 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
960 * @key_data: key read from console
961 * Return: status code
962 *
963 * This function implements the ReadKeyStrokeEx service of the
964 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
965 *
966 * See the Unified Extensible Firmware Interface (UEFI) specification for
967 * details.
968 */
969static efi_status_t EFIAPI efi_cin_read_key_stroke_ex(
970 struct efi_simple_text_input_ex_protocol *this,
971 struct efi_key_data *key_data)
972{
973 efi_status_t ret = EFI_SUCCESS;
974
975 EFI_ENTRY("%p, %p", this, key_data);
976
977 /* Check parameters */
978 if (!this || !key_data) {
979 ret = EFI_INVALID_PARAMETER;
980 goto out;
981 }
982
983 /* We don't do interrupts, so check for timers cooperatively */
984 efi_timer_check();
985
986 /* Enable console input after ExitBootServices */
987 efi_cin_check();
988
989 if (!key_available) {
990 ret = EFI_NOT_READY;
991 goto out;
992 }
Heinrich Schuchardt00b00a12019-04-06 20:59:24 +0200993 /*
994 * CTRL+A - CTRL+Z have to be signaled as a - z.
995 * SHIFT+CTRL+A - SHIFT+CTRL+Z have to be signaled as A - Z.
996 */
997 switch (next_key.key.unicode_char) {
998 case 0x01 ... 0x07:
999 case 0x0b ... 0x0c:
1000 case 0x0e ... 0x1a:
1001 if (!(next_key.key_state.key_toggle_state &
1002 EFI_CAPS_LOCK_ACTIVE) ^
1003 !(next_key.key_state.key_shift_state &
1004 (EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED)))
1005 next_key.key.unicode_char += 0x40;
1006 else
1007 next_key.key.unicode_char += 0x60;
1008 }
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001009 *key_data = next_key;
1010 key_available = false;
1011 efi_con_in.wait_for_key->is_signaled = false;
Heinrich Schuchardt00b00a12019-04-06 20:59:24 +02001012
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001013out:
1014 return EFI_EXIT(ret);
1015}
1016
1017/**
1018 * efi_cin_set_state() - set toggle key state
1019 *
1020 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
Heinrich Schuchardta41ccf92019-05-18 17:07:52 +02001021 * @key_toggle_state: pointer to key toggle state
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001022 * Return: status code
1023 *
1024 * This function implements the SetState service of the
1025 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
1026 *
1027 * See the Unified Extensible Firmware Interface (UEFI) specification for
1028 * details.
1029 */
1030static efi_status_t EFIAPI efi_cin_set_state(
1031 struct efi_simple_text_input_ex_protocol *this,
Heinrich Schuchardta41ccf92019-05-18 17:07:52 +02001032 u8 *key_toggle_state)
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001033{
Heinrich Schuchardta41ccf92019-05-18 17:07:52 +02001034 EFI_ENTRY("%p, %p", this, key_toggle_state);
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001035 /*
1036 * U-Boot supports multiple console input sources like serial and
1037 * net console for which a key toggle state cannot be set at all.
1038 *
1039 * According to the UEFI specification it is allowable to not implement
1040 * this service.
1041 */
1042 return EFI_EXIT(EFI_UNSUPPORTED);
1043}
1044
1045/**
1046 * efi_cin_register_key_notify() - register key notification function
1047 *
1048 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
1049 * @key_data: key to be notified
1050 * @key_notify_function: function to be called if the key is pressed
1051 * @notify_handle: handle for unregistering the notification
1052 * Return: status code
1053 *
1054 * This function implements the SetState service of the
1055 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
1056 *
1057 * See the Unified Extensible Firmware Interface (UEFI) specification for
1058 * details.
1059 */
1060static efi_status_t EFIAPI efi_cin_register_key_notify(
1061 struct efi_simple_text_input_ex_protocol *this,
1062 struct efi_key_data *key_data,
1063 efi_status_t (EFIAPI *key_notify_function)(
1064 struct efi_key_data *key_data),
1065 void **notify_handle)
1066{
Heinrich Schuchardt695691e2018-09-11 22:38:12 +02001067 efi_status_t ret = EFI_SUCCESS;
1068 struct efi_cin_notify_function *notify_function;
1069
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001070 EFI_ENTRY("%p, %p, %p, %p",
1071 this, key_data, key_notify_function, notify_handle);
Heinrich Schuchardt695691e2018-09-11 22:38:12 +02001072
1073 /* Check parameters */
1074 if (!this || !key_data || !key_notify_function || !notify_handle) {
1075 ret = EFI_INVALID_PARAMETER;
1076 goto out;
1077 }
1078
1079 EFI_PRINT("u+%04x, sc %04x, sh %08x, tg %02x\n",
1080 key_data->key.unicode_char,
1081 key_data->key.scan_code,
1082 key_data->key_state.key_shift_state,
1083 key_data->key_state.key_toggle_state);
1084
1085 notify_function = calloc(1, sizeof(struct efi_cin_notify_function));
1086 if (!notify_function) {
1087 ret = EFI_OUT_OF_RESOURCES;
1088 goto out;
1089 }
1090 notify_function->key = *key_data;
1091 notify_function->function = key_notify_function;
1092 list_add_tail(&notify_function->link, &cin_notify_functions);
1093 *notify_handle = notify_function;
1094out:
1095 return EFI_EXIT(ret);
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001096}
1097
1098/**
1099 * efi_cin_unregister_key_notify() - unregister key notification function
1100 *
1101 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
1102 * @notification_handle: handle received when registering
1103 * Return: status code
1104 *
1105 * This function implements the SetState service of the
1106 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
1107 *
1108 * See the Unified Extensible Firmware Interface (UEFI) specification for
1109 * details.
1110 */
1111static efi_status_t EFIAPI efi_cin_unregister_key_notify(
1112 struct efi_simple_text_input_ex_protocol *this,
1113 void *notification_handle)
1114{
Heinrich Schuchardt695691e2018-09-11 22:38:12 +02001115 efi_status_t ret = EFI_INVALID_PARAMETER;
1116 struct efi_cin_notify_function *item, *notify_function =
1117 notification_handle;
1118
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001119 EFI_ENTRY("%p, %p", this, notification_handle);
Heinrich Schuchardt695691e2018-09-11 22:38:12 +02001120
1121 /* Check parameters */
1122 if (!this || !notification_handle)
1123 goto out;
1124
1125 list_for_each_entry(item, &cin_notify_functions, link) {
1126 if (item == notify_function) {
1127 ret = EFI_SUCCESS;
1128 break;
1129 }
1130 }
1131 if (ret != EFI_SUCCESS)
1132 goto out;
1133
1134 /* Remove the notify function */
1135 list_del(&notify_function->link);
1136 free(notify_function);
1137out:
1138 return EFI_EXIT(ret);
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001139}
1140
1141
1142/**
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001143 * efi_cin_reset() - drain the input buffer
1144 *
1145 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
1146 * @extended_verification: allow for exhaustive verification
1147 * Return: status code
1148 *
1149 * This function implements the Reset service of the
1150 * EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
1151 *
1152 * See the Unified Extensible Firmware Interface (UEFI) specification for
1153 * details.
1154 */
1155static efi_status_t EFIAPI efi_cin_reset
1156 (struct efi_simple_text_input_protocol *this,
1157 bool extended_verification)
1158{
1159 efi_status_t ret = EFI_SUCCESS;
1160
1161 EFI_ENTRY("%p, %d", this, extended_verification);
1162
1163 /* Check parameters */
1164 if (!this) {
1165 ret = EFI_INVALID_PARAMETER;
1166 goto out;
1167 }
1168
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001169 efi_cin_empty_buffer();
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001170out:
1171 return EFI_EXIT(ret);
1172}
1173
1174/**
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001175 * efi_cin_read_key_stroke() - read key stroke
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001176 *
1177 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
1178 * @key: key read from console
1179 * Return: status code
1180 *
1181 * This function implements the ReadKeyStroke service of the
1182 * EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
1183 *
1184 * See the Unified Extensible Firmware Interface (UEFI) specification for
1185 * details.
1186 */
1187static efi_status_t EFIAPI efi_cin_read_key_stroke
1188 (struct efi_simple_text_input_protocol *this,
1189 struct efi_input_key *key)
1190{
1191 efi_status_t ret = EFI_SUCCESS;
1192
1193 EFI_ENTRY("%p, %p", this, key);
1194
1195 /* Check parameters */
1196 if (!this || !key) {
1197 ret = EFI_INVALID_PARAMETER;
1198 goto out;
1199 }
1200
1201 /* We don't do interrupts, so check for timers cooperatively */
1202 efi_timer_check();
1203
1204 /* Enable console input after ExitBootServices */
1205 efi_cin_check();
1206
1207 if (!key_available) {
1208 ret = EFI_NOT_READY;
1209 goto out;
1210 }
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001211 *key = next_key.key;
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001212 key_available = false;
1213 efi_con_in.wait_for_key->is_signaled = false;
1214out:
1215 return EFI_EXIT(ret);
Alexander Graf4aacacc2016-03-04 01:10:00 +01001216}
1217
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001218static struct efi_simple_text_input_ex_protocol efi_con_in_ex = {
1219 .reset = efi_cin_reset_ex,
1220 .read_key_stroke_ex = efi_cin_read_key_stroke_ex,
1221 .wait_for_key_ex = NULL,
1222 .set_state = efi_cin_set_state,
1223 .register_key_notify = efi_cin_register_key_notify,
1224 .unregister_key_notify = efi_cin_unregister_key_notify,
1225};
1226
Heinrich Schuchardt3dabffd2018-09-08 10:20:10 +02001227struct efi_simple_text_input_protocol efi_con_in = {
Alexander Graf4aacacc2016-03-04 01:10:00 +01001228 .reset = efi_cin_reset,
1229 .read_key_stroke = efi_cin_read_key_stroke,
1230 .wait_for_key = NULL,
1231};
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001232
1233static struct efi_event *console_timer_event;
1234
Heinrich Schuchardtd8b878a2018-01-19 20:24:51 +01001235/*
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001236 * efi_console_timer_notify() - notify the console timer event
Heinrich Schuchardtd8b878a2018-01-19 20:24:51 +01001237 *
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001238 * @event: console timer event
1239 * @context: not used
Heinrich Schuchardtd8b878a2018-01-19 20:24:51 +01001240 */
xypron.glpk@gmx.de0ce42dc2017-07-20 05:26:07 +02001241static void EFIAPI efi_console_timer_notify(struct efi_event *event,
1242 void *context)
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001243{
1244 EFI_ENTRY("%p, %p", event, context);
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001245 efi_cin_check();
1246 EFI_EXIT(EFI_SUCCESS);
1247}
Heinrich Schuchardtd8b878a2018-01-19 20:24:51 +01001248
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001249/**
1250 * efi_key_notify() - notify the wait for key event
1251 *
1252 * @event: wait for key event
1253 * @context: not used
1254 */
1255static void EFIAPI efi_key_notify(struct efi_event *event, void *context)
1256{
1257 EFI_ENTRY("%p, %p", event, context);
1258 efi_cin_check();
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001259 EFI_EXIT(EFI_SUCCESS);
1260}
1261
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001262/**
1263 * efi_console_register() - install the console protocols
1264 *
1265 * This function is called from do_bootefi_exec().
Heinrich Schuchardta92e9ab2018-10-02 06:08:26 +02001266 *
1267 * Return: status code
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001268 */
Heinrich Schuchardta92e9ab2018-10-02 06:08:26 +02001269efi_status_t efi_console_register(void)
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001270{
1271 efi_status_t r;
Heinrich Schuchardt81244ea2022-02-04 20:47:09 +01001272 struct efi_device_path *dp;
Rob Clark49f7b4b2017-07-24 10:39:01 -04001273
Heinrich Schuchardt81244ea2022-02-04 20:47:09 +01001274 /* Install protocols on root node */
1275 r = EFI_CALL(efi_install_multiple_protocol_interfaces
1276 (&efi_root,
1277 &efi_guid_text_output_protocol, &efi_con_out,
1278 &efi_guid_text_input_protocol, &efi_con_in,
1279 &efi_guid_text_input_ex_protocol, &efi_con_in_ex,
1280 NULL));
Alexander Graf36bab912018-09-04 14:59:11 +02001281
Heinrich Schuchardt81244ea2022-02-04 20:47:09 +01001282 /* Create console node and install device path protocols */
1283 if (CONFIG_IS_ENABLED(DM_SERIAL)) {
1284 dp = efi_dp_from_uart();
1285 if (!dp)
1286 goto out_of_memory;
Alexander Graf36bab912018-09-04 14:59:11 +02001287
Heinrich Schuchardt81244ea2022-02-04 20:47:09 +01001288 /* Hook UART up to the device list */
1289 efi_add_handle(&uart_obj);
Alexander Graf36bab912018-09-04 14:59:11 +02001290
Heinrich Schuchardt81244ea2022-02-04 20:47:09 +01001291 /* Install device path */
1292 r = efi_add_protocol(&uart_obj, &efi_guid_device_path, dp);
1293 if (r != EFI_SUCCESS)
1294 goto out_of_memory;
1295 }
Rob Clark49f7b4b2017-07-24 10:39:01 -04001296
Heinrich Schuchardt580c13b2017-10-26 19:25:59 +02001297 /* Create console events */
Heinrich Schuchardtbf7f1692018-02-18 15:17:52 +01001298 r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK, efi_key_notify,
1299 NULL, NULL, &efi_con_in.wait_for_key);
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001300 if (r != EFI_SUCCESS) {
1301 printf("ERROR: Failed to register WaitForKey event\n");
1302 return r;
1303 }
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001304 efi_con_in_ex.wait_for_key_ex = efi_con_in.wait_for_key;
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001305 r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
Heinrich Schuchardtbf7f1692018-02-18 15:17:52 +01001306 efi_console_timer_notify, NULL, NULL,
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001307 &console_timer_event);
1308 if (r != EFI_SUCCESS) {
1309 printf("ERROR: Failed to register console event\n");
1310 return r;
1311 }
1312 /* 5000 ns cycle is sufficient for 2 MBaud */
1313 r = efi_set_timer(console_timer_event, EFI_TIMER_PERIODIC, 50);
1314 if (r != EFI_SUCCESS)
1315 printf("ERROR: Failed to set console timer\n");
1316 return r;
Heinrich Schuchardt580c13b2017-10-26 19:25:59 +02001317out_of_memory:
Heinrich Schuchardt6e8eff22018-09-08 19:57:24 +02001318 printf("ERROR: Out of memory\n");
Heinrich Schuchardt580c13b2017-10-26 19:25:59 +02001319 return r;
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001320}