blob: ba68a15017243dd416c42a2da3950cec65408a33 [file] [log] [blame]
Tom Rini70df9d62018-05-07 17:02:21 -04001// SPDX-License-Identifier: GPL-2.0+
Alexander Graf4aacacc2016-03-04 01:10:00 +01002/*
3 * EFI application console interface
4 *
5 * Copyright (c) 2016 Alexander Graf
Alexander Graf4aacacc2016-03-04 01:10:00 +01006 */
7
8#include <common.h>
Rob Clark0d138cf2017-09-09 06:47:40 -04009#include <charset.h>
Simon Glass9bc15642020-02-03 07:36:16 -070010#include <malloc.h>
Simon Glass495a5dc2019-11-14 12:57:30 -070011#include <time.h>
Rob Clark3863b712017-09-13 18:05:43 -040012#include <dm/device.h>
Alexander Graf4aacacc2016-03-04 01:10:00 +010013#include <efi_loader.h>
Simon Glass0af6e2d2019-08-01 09:46:52 -060014#include <env.h>
Rob Clark3863b712017-09-13 18:05:43 -040015#include <stdio_dev.h>
16#include <video_console.h>
Heinrich Schuchardte5c93172020-12-27 14:47:50 +010017#include <linux/delay.h>
Alexander Graf4aacacc2016-03-04 01:10:00 +010018
Emmanuel Vadota074d5d2016-11-08 06:03:29 +010019#define EFI_COUT_MODE_2 2
20#define EFI_MAX_COUT_MODE 3
21
22struct cout_mode {
23 unsigned long columns;
24 unsigned long rows;
25 int present;
26};
27
Heinrich Schuchardt81244ea2022-02-04 20:47:09 +010028__maybe_unused static struct efi_object uart_obj;
29
Emmanuel Vadota074d5d2016-11-08 06:03:29 +010030static struct cout_mode efi_cout_modes[] = {
31 /* EFI Mode 0 is 80x25 and always present */
32 {
33 .columns = 80,
34 .rows = 25,
35 .present = 1,
36 },
37 /* EFI Mode 1 is always 80x50 */
38 {
39 .columns = 80,
40 .rows = 50,
41 .present = 0,
42 },
43 /* Value are unknown until we query the console */
44 {
45 .columns = 0,
46 .rows = 0,
47 .present = 0,
48 },
49};
50
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +020051const efi_guid_t efi_guid_text_input_ex_protocol =
52 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
Heinrich Schuchardt580c13b2017-10-26 19:25:59 +020053const efi_guid_t efi_guid_text_input_protocol =
54 EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID;
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +020055const efi_guid_t efi_guid_text_output_protocol =
56 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID;
Alexander Graf4aacacc2016-03-04 01:10:00 +010057
58#define cESC '\x1b'
59#define ESC "\x1b"
60
Emmanuel Vadota074d5d2016-11-08 06:03:29 +010061/* Default to mode 0 */
Alexander Graf4aacacc2016-03-04 01:10:00 +010062static struct simple_text_output_mode efi_con_mode = {
Emmanuel Vadota074d5d2016-11-08 06:03:29 +010063 .max_mode = 1,
Alexander Graf4aacacc2016-03-04 01:10:00 +010064 .mode = 0,
65 .attribute = 0,
66 .cursor_column = 0,
67 .cursor_row = 0,
68 .cursor_visible = 1,
69};
70
Matthias Brugger29c6f5f2019-03-05 12:50:18 +010071static int term_get_char(s32 *c)
72{
73 u64 timeout;
74
75 /* Wait up to 100 ms for a character */
76 timeout = timer_get_us() + 100000;
77
78 while (!tstc())
79 if (timer_get_us() > timeout)
80 return 1;
81
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +020082 *c = getchar();
Matthias Brugger29c6f5f2019-03-05 12:50:18 +010083 return 0;
84}
85
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +020086/**
Heinrich Schuchardt77135c22018-05-16 18:17:38 +020087 * Receive and parse a reply from the terminal.
88 *
89 * @n: array of return values
90 * @num: number of return values expected
91 * @end_char: character indicating end of terminal message
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +020092 * Return: non-zero indicates error
Heinrich Schuchardt77135c22018-05-16 18:17:38 +020093 */
94static int term_read_reply(int *n, int num, char end_char)
Alexander Graf4aacacc2016-03-04 01:10:00 +010095{
Matthias Brugger29c6f5f2019-03-05 12:50:18 +010096 s32 c;
Alexander Graf4aacacc2016-03-04 01:10:00 +010097 int i = 0;
98
Matthias Brugger29c6f5f2019-03-05 12:50:18 +010099 if (term_get_char(&c) || c != cESC)
Alexander Graf4aacacc2016-03-04 01:10:00 +0100100 return -1;
Matthias Brugger29c6f5f2019-03-05 12:50:18 +0100101
102 if (term_get_char(&c) || c != '[')
Alexander Graf4aacacc2016-03-04 01:10:00 +0100103 return -1;
104
105 n[0] = 0;
106 while (1) {
Matthias Brugger29c6f5f2019-03-05 12:50:18 +0100107 if (!term_get_char(&c)) {
108 if (c == ';') {
109 i++;
110 if (i >= num)
111 return -1;
112 n[i] = 0;
113 continue;
114 } else if (c == end_char) {
115 break;
116 } else if (c > '9' || c < '0') {
Alexander Graf4aacacc2016-03-04 01:10:00 +0100117 return -1;
Matthias Brugger29c6f5f2019-03-05 12:50:18 +0100118 }
119
120 /* Read one more decimal position */
121 n[i] *= 10;
122 n[i] += c - '0';
123 } else {
Alexander Graf4aacacc2016-03-04 01:10:00 +0100124 return -1;
125 }
Alexander Graf4aacacc2016-03-04 01:10:00 +0100126 }
Heinrich Schuchardt77135c22018-05-16 18:17:38 +0200127 if (i != num - 1)
128 return -1;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100129
130 return 0;
131}
132
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200133/**
134 * efi_cout_output_string() - write Unicode string to console
135 *
136 * This function implements the OutputString service of the simple text output
137 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
138 * for details.
139 *
140 * @this: simple text output protocol
141 * @string: u16 string
142 * Return: status code
143 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100144static efi_status_t EFIAPI efi_cout_output_string(
145 struct efi_simple_text_output_protocol *this,
Heinrich Schuchardt84494282021-01-05 07:50:09 +0100146 const u16 *string)
Alexander Graf4aacacc2016-03-04 01:10:00 +0100147{
Rob Clark1ef185d2017-09-13 18:05:44 -0400148 struct simple_text_output_mode *con = &efi_con_mode;
149 struct cout_mode *mode = &efi_cout_modes[con->mode];
Heinrich Schuchardta419d1d2018-08-31 21:31:32 +0200150 char *buf, *pos;
Heinrich Schuchardt84494282021-01-05 07:50:09 +0100151 const u16 *p;
Heinrich Schuchardta419d1d2018-08-31 21:31:32 +0200152 efi_status_t ret = EFI_SUCCESS;
Rob Clark1ef185d2017-09-13 18:05:44 -0400153
Heinrich Schuchardta419d1d2018-08-31 21:31:32 +0200154 EFI_ENTRY("%p, %p", this, string);
Rob Clark1ef185d2017-09-13 18:05:44 -0400155
Heinrich Schuchardte60b2982019-05-18 18:11:54 +0200156 if (!this || !string) {
157 ret = EFI_INVALID_PARAMETER;
158 goto out;
159 }
160
Heinrich Schuchardta419d1d2018-08-31 21:31:32 +0200161 buf = malloc(utf16_utf8_strlen(string) + 1);
162 if (!buf) {
163 ret = EFI_OUT_OF_RESOURCES;
164 goto out;
165 }
166 pos = buf;
167 utf16_utf8_strcpy(&pos, string);
Rob Clark1ef185d2017-09-13 18:05:44 -0400168 fputs(stdout, buf);
Heinrich Schuchardta419d1d2018-08-31 21:31:32 +0200169 free(buf);
Rob Clark1ef185d2017-09-13 18:05:44 -0400170
Heinrich Schuchardt8aaeed92018-04-29 16:24:25 +0200171 /*
172 * Update the cursor position.
173 *
174 * The UEFI spec provides advance rules for U+0000, U+0008, U+000A,
Heinrich Schuchardtda88da82019-09-04 21:13:45 +0200175 * and U000D. All other control characters are ignored. Any non-control
176 * character increase the column by one.
Heinrich Schuchardt8aaeed92018-04-29 16:24:25 +0200177 */
178 for (p = string; *p; ++p) {
Rob Clark1ef185d2017-09-13 18:05:44 -0400179 switch (*p) {
Heinrich Schuchardt8aaeed92018-04-29 16:24:25 +0200180 case '\b': /* U+0008, backspace */
Heinrich Schuchardtda88da82019-09-04 21:13:45 +0200181 if (con->cursor_column)
182 con->cursor_column--;
Rob Clark1ef185d2017-09-13 18:05:44 -0400183 break;
Heinrich Schuchardt8aaeed92018-04-29 16:24:25 +0200184 case '\n': /* U+000A, newline */
Rob Clark1ef185d2017-09-13 18:05:44 -0400185 con->cursor_column = 0;
186 con->cursor_row++;
187 break;
Heinrich Schuchardt8aaeed92018-04-29 16:24:25 +0200188 case '\r': /* U+000D, carriage-return */
189 con->cursor_column = 0;
Rob Clark1ef185d2017-09-13 18:05:44 -0400190 break;
Heinrich Schuchardt8aaeed92018-04-29 16:24:25 +0200191 case 0xd800 ... 0xdbff:
192 /*
193 * Ignore high surrogates, we do not want to count a
194 * Unicode character twice.
195 */
Rob Clark1ef185d2017-09-13 18:05:44 -0400196 break;
197 default:
Heinrich Schuchardtda88da82019-09-04 21:13:45 +0200198 /* Exclude control codes */
199 if (*p > 0x1f)
200 con->cursor_column++;
Rob Clark1ef185d2017-09-13 18:05:44 -0400201 break;
202 }
203 if (con->cursor_column >= mode->columns) {
204 con->cursor_column = 0;
205 con->cursor_row++;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100206 }
Heinrich Schuchardtda88da82019-09-04 21:13:45 +0200207 /*
208 * When we exceed the row count the terminal will scroll up one
209 * line. We have to adjust the cursor position.
210 */
211 if (con->cursor_row >= mode->rows && con->cursor_row)
212 con->cursor_row--;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100213 }
214
Heinrich Schuchardta419d1d2018-08-31 21:31:32 +0200215out:
216 return EFI_EXIT(ret);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100217}
218
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200219/**
220 * efi_cout_test_string() - test writing Unicode string to console
221 *
222 * This function implements the TestString service of the simple text output
223 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
224 * for details.
225 *
226 * As in OutputString we simply convert UTF-16 to UTF-8 there are no unsupported
227 * code points and we can always return EFI_SUCCESS.
228 *
229 * @this: simple text output protocol
230 * @string: u16 string
231 * Return: status code
232 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100233static efi_status_t EFIAPI efi_cout_test_string(
234 struct efi_simple_text_output_protocol *this,
Heinrich Schuchardt84494282021-01-05 07:50:09 +0100235 const u16 *string)
Alexander Graf4aacacc2016-03-04 01:10:00 +0100236{
237 EFI_ENTRY("%p, %p", this, string);
238 return EFI_EXIT(EFI_SUCCESS);
239}
240
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200241/**
242 * cout_mode_matches() - check if mode has given terminal size
243 *
244 * @mode: text mode
245 * @rows: number of rows
246 * @cols: number of columns
247 * Return: true if number of rows and columns matches the mode and
248 * the mode is present
249 */
Emmanuel Vadota074d5d2016-11-08 06:03:29 +0100250static bool cout_mode_matches(struct cout_mode *mode, int rows, int cols)
251{
252 if (!mode->present)
253 return false;
254
255 return (mode->rows == rows) && (mode->columns == cols);
256}
257
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200258/**
Heinrich Schuchardtae165ef2021-03-16 12:56:57 +0100259 * query_console_serial() - query serial console size
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200260 *
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200261 * When using a serial console or the net console we can only devise the
262 * terminal size by querying the terminal using ECMA-48 control sequences.
263 *
Heinrich Schuchardtdc305ad2019-09-05 20:37:13 +0200264 * @rows: pointer to return number of rows
265 * @cols: pointer to return number of columns
266 * Returns: 0 on success
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200267 */
Rob Clark1e948922017-09-13 18:05:42 -0400268static int query_console_serial(int *rows, int *cols)
269{
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200270 int ret = 0;
271 int n[2];
Rob Clark1e948922017-09-13 18:05:42 -0400272
273 /* Empty input buffer */
274 while (tstc())
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200275 getchar();
Rob Clark1e948922017-09-13 18:05:42 -0400276
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200277 /*
278 * Not all terminals understand CSI [18t for querying the console size.
279 * We should adhere to escape sequences documented in the console_codes
Heinrich Schuchardt5e96f422018-10-18 21:51:38 +0200280 * man page and the ECMA-48 standard.
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200281 *
282 * So here we follow a different approach. We position the cursor to the
283 * bottom right and query its position. Before leaving the function we
284 * restore the original cursor position.
285 */
286 printf(ESC "7" /* Save cursor position */
287 ESC "[r" /* Set scrolling region to full window */
288 ESC "[999;999H" /* Move to bottom right corner */
289 ESC "[6n"); /* Query cursor position */
Rob Clark1e948922017-09-13 18:05:42 -0400290
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200291 /* Read {rows,cols} */
292 if (term_read_reply(n, 2, 'R')) {
293 ret = 1;
294 goto out;
295 }
Rob Clark1e948922017-09-13 18:05:42 -0400296
Heinrich Schuchardt5965d2e2018-09-15 23:52:07 +0200297 *cols = n[1];
298 *rows = n[0];
299out:
300 printf(ESC "8"); /* Restore cursor position */
301 return ret;
Rob Clark1e948922017-09-13 18:05:42 -0400302}
303
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200304/**
Heinrich Schuchardtae165ef2021-03-16 12:56:57 +0100305 * query_vidconsole() - query video console size
306 *
307 *
308 * @rows: pointer to return number of rows
309 * @cols: pointer to return number of columns
310 * Returns: 0 on success
311 */
312static int __maybe_unused query_vidconsole(int *rows, int *cols)
313{
314 const char *stdout_name = env_get("stdout");
315 struct stdio_dev *stdout_dev;
316 struct udevice *dev;
317 struct vidconsole_priv *priv;
318
319 if (!stdout_name || strncmp(stdout_name, "vidconsole", 10))
320 return -ENODEV;
321 stdout_dev = stdio_get_by_name("vidconsole");
322 if (!stdout_dev)
323 return -ENODEV;
324 dev = stdout_dev->priv;
325 if (!dev)
326 return -ENODEV;
327 priv = dev_get_uclass_priv(dev);
328 if (!priv)
329 return -ENODEV;
330 *rows = priv->rows;
331 *cols = priv->cols;
332 return 0;
333}
334
335/**
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200336 * query_console_size() - update the mode table.
Heinrich Schuchardt75b4e692018-04-29 20:02:46 +0200337 *
338 * By default the only mode available is 80x25. If the console has at least 50
339 * lines, enable mode 80x50. If we can query the console size and it is neither
340 * 80x25 nor 80x50, set it as an additional mode.
341 */
342static void query_console_size(void)
343{
Alexander Graf28795322018-06-03 15:51:17 +0200344 int rows = 25, cols = 80;
Heinrich Schuchardtae165ef2021-03-16 12:56:57 +0100345 int ret = -ENODEV;
Heinrich Schuchardt75b4e692018-04-29 20:02:46 +0200346
Heinrich Schuchardtc86d2bb2021-06-29 10:09:14 +0200347 if (IS_ENABLED(CONFIG_DM_VIDEO))
Heinrich Schuchardtae165ef2021-03-16 12:56:57 +0100348 ret = query_vidconsole(&rows, &cols);
349 if (ret)
350 ret = query_console_serial(&rows, &cols);
351 if (ret)
Heinrich Schuchardt75b4e692018-04-29 20:02:46 +0200352 return;
Heinrich Schuchardt75b4e692018-04-29 20:02:46 +0200353
354 /* Test if we can have Mode 1 */
355 if (cols >= 80 && rows >= 50) {
356 efi_cout_modes[1].present = 1;
357 efi_con_mode.max_mode = 2;
358 }
359
360 /*
361 * Install our mode as mode 2 if it is different
362 * than mode 0 or 1 and set it as the currently selected mode
363 */
364 if (!cout_mode_matches(&efi_cout_modes[0], rows, cols) &&
365 !cout_mode_matches(&efi_cout_modes[1], rows, cols)) {
366 efi_cout_modes[EFI_COUT_MODE_2].columns = cols;
367 efi_cout_modes[EFI_COUT_MODE_2].rows = rows;
368 efi_cout_modes[EFI_COUT_MODE_2].present = 1;
369 efi_con_mode.max_mode = EFI_MAX_COUT_MODE;
370 efi_con_mode.mode = EFI_COUT_MODE_2;
371 }
372}
373
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200374
375/**
376 * efi_cout_query_mode() - get terminal size for a text mode
377 *
378 * This function implements the QueryMode service of the simple text output
379 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
380 * for details.
381 *
382 * @this: simple text output protocol
383 * @mode_number: mode number to retrieve information on
384 * @columns: number of columns
385 * @rows: number of rows
386 * Return: status code
387 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100388static efi_status_t EFIAPI efi_cout_query_mode(
389 struct efi_simple_text_output_protocol *this,
390 unsigned long mode_number, unsigned long *columns,
391 unsigned long *rows)
392{
393 EFI_ENTRY("%p, %ld, %p, %p", this, mode_number, columns, rows);
394
Emmanuel Vadota074d5d2016-11-08 06:03:29 +0100395 if (mode_number >= efi_con_mode.max_mode)
396 return EFI_EXIT(EFI_UNSUPPORTED);
397
398 if (efi_cout_modes[mode_number].present != 1)
399 return EFI_EXIT(EFI_UNSUPPORTED);
400
Alexander Graf4aacacc2016-03-04 01:10:00 +0100401 if (columns)
Emmanuel Vadota074d5d2016-11-08 06:03:29 +0100402 *columns = efi_cout_modes[mode_number].columns;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100403 if (rows)
Emmanuel Vadota074d5d2016-11-08 06:03:29 +0100404 *rows = efi_cout_modes[mode_number].rows;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100405
406 return EFI_EXIT(EFI_SUCCESS);
407}
408
Rob Clark87ef0012017-10-10 08:23:01 -0400409static const struct {
410 unsigned int fg;
411 unsigned int bg;
412} color[] = {
413 { 30, 40 }, /* 0: black */
414 { 34, 44 }, /* 1: blue */
415 { 32, 42 }, /* 2: green */
416 { 36, 46 }, /* 3: cyan */
417 { 31, 41 }, /* 4: red */
418 { 35, 45 }, /* 5: magenta */
Heinrich Schuchardt6e8eff22018-09-08 19:57:24 +0200419 { 33, 43 }, /* 6: brown, map to yellow as EDK2 does*/
420 { 37, 47 }, /* 7: light gray, map to white */
Rob Clark87ef0012017-10-10 08:23:01 -0400421};
422
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200423/**
424 * efi_cout_set_attribute() - set fore- and background color
425 *
426 * This function implements the SetAttribute service of the simple text output
427 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
428 * for details.
429 *
430 * @this: simple text output protocol
431 * @attribute: foreground color - bits 0-3, background color - bits 4-6
432 * Return: status code
433 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100434static efi_status_t EFIAPI efi_cout_set_attribute(
435 struct efi_simple_text_output_protocol *this,
436 unsigned long attribute)
437{
Rob Clark87ef0012017-10-10 08:23:01 -0400438 unsigned int bold = EFI_ATTR_BOLD(attribute);
439 unsigned int fg = EFI_ATTR_FG(attribute);
440 unsigned int bg = EFI_ATTR_BG(attribute);
441
Alexander Graf4aacacc2016-03-04 01:10:00 +0100442 EFI_ENTRY("%p, %lx", this, attribute);
443
Heinrich Schuchardt1e129622019-06-14 07:16:57 +0200444 efi_con_mode.attribute = attribute;
Rob Clark87ef0012017-10-10 08:23:01 -0400445 if (attribute)
446 printf(ESC"[%u;%u;%um", bold, color[fg].fg, color[bg].bg);
447 else
448 printf(ESC"[0;37;40m");
449
450 return EFI_EXIT(EFI_SUCCESS);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100451}
452
Heinrich Schuchardt7995cbe2019-12-22 07:15:55 +0000453/**
454 * efi_cout_clear_screen() - clear screen
455 *
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200456 * This function implements the ClearScreen service of the simple text output
457 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
458 * for details.
Heinrich Schuchardt7995cbe2019-12-22 07:15:55 +0000459 *
460 * @this: pointer to the protocol instance
461 * Return: status code
462 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100463static efi_status_t EFIAPI efi_cout_clear_screen(
464 struct efi_simple_text_output_protocol *this)
465{
466 EFI_ENTRY("%p", this);
467
Heinrich Schuchardt7995cbe2019-12-22 07:15:55 +0000468 /*
469 * The Linux console wants both a clear and a home command. The video
470 * uclass does not support <ESC>[H without coordinates, yet.
471 */
472 printf(ESC "[2J" ESC "[1;1H");
Heinrich Schuchardt2d099322018-07-05 08:18:00 +0200473 efi_con_mode.cursor_column = 0;
474 efi_con_mode.cursor_row = 0;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100475
476 return EFI_EXIT(EFI_SUCCESS);
477}
478
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200479/**
480 * efi_cout_clear_set_mode() - set text model
481 *
482 * This function implements the SetMode service of the simple text output
483 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
484 * for details.
485 *
486 * @this: pointer to the protocol instance
487 * @mode_number: number of the text mode to set
488 * Return: status code
489 */
Heinrich Schuchardt757cc4a2019-06-14 07:20:51 +0200490static efi_status_t EFIAPI efi_cout_set_mode(
491 struct efi_simple_text_output_protocol *this,
492 unsigned long mode_number)
493{
494 EFI_ENTRY("%p, %ld", this, mode_number);
495
496 if (mode_number >= efi_con_mode.max_mode)
497 return EFI_EXIT(EFI_UNSUPPORTED);
Heinrich Schuchardt6a6afa72019-09-04 22:46:13 +0200498
499 if (!efi_cout_modes[mode_number].present)
500 return EFI_EXIT(EFI_UNSUPPORTED);
501
Heinrich Schuchardt757cc4a2019-06-14 07:20:51 +0200502 efi_con_mode.mode = mode_number;
503 EFI_CALL(efi_cout_clear_screen(this));
504
505 return EFI_EXIT(EFI_SUCCESS);
506}
507
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200508/**
509 * efi_cout_reset() - reset the terminal
510 *
511 * This function implements the Reset service of the simple text output
512 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
513 * for details.
514 *
515 * @this: pointer to the protocol instance
516 * @extended_verification: if set an extended verification may be executed
517 * Return: status code
518 */
Heinrich Schuchardt09866c22018-07-05 19:58:07 +0200519static efi_status_t EFIAPI efi_cout_reset(
520 struct efi_simple_text_output_protocol *this,
521 char extended_verification)
522{
523 EFI_ENTRY("%p, %d", this, extended_verification);
524
525 /* Clear screen */
526 EFI_CALL(efi_cout_clear_screen(this));
527 /* Set default colors */
Heinrich Schuchardt1e129622019-06-14 07:16:57 +0200528 efi_con_mode.attribute = 0x07;
Heinrich Schuchardt09866c22018-07-05 19:58:07 +0200529 printf(ESC "[0;37;40m");
530
531 return EFI_EXIT(EFI_SUCCESS);
532}
533
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200534/**
535 * efi_cout_set_cursor_position() - reset the terminal
536 *
537 * This function implements the SetCursorPosition service of the simple text
538 * output protocol. See the Unified Extensible Firmware Interface (UEFI)
539 * specification for details.
540 *
541 * @this: pointer to the protocol instance
542 * @column: column to move to
543 * @row: row to move to
544 * Return: status code
545 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100546static efi_status_t EFIAPI efi_cout_set_cursor_position(
547 struct efi_simple_text_output_protocol *this,
548 unsigned long column, unsigned long row)
549{
Heinrich Schuchardtdcac1d92018-09-14 18:49:26 +0200550 efi_status_t ret = EFI_SUCCESS;
551 struct simple_text_output_mode *con = &efi_con_mode;
552 struct cout_mode *mode = &efi_cout_modes[con->mode];
553
Alexander Graf4aacacc2016-03-04 01:10:00 +0100554 EFI_ENTRY("%p, %ld, %ld", this, column, row);
555
Heinrich Schuchardtdcac1d92018-09-14 18:49:26 +0200556 /* Check parameters */
557 if (!this) {
558 ret = EFI_INVALID_PARAMETER;
559 goto out;
560 }
561 if (row >= mode->rows || column >= mode->columns) {
562 ret = EFI_UNSUPPORTED;
563 goto out;
564 }
565
566 /*
567 * Set cursor position by sending CSI H.
568 * EFI origin is [0, 0], terminal origin is [1, 1].
569 */
570 printf(ESC "[%d;%dH", (int)row + 1, (int)column + 1);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100571 efi_con_mode.cursor_column = column;
572 efi_con_mode.cursor_row = row;
Heinrich Schuchardtdcac1d92018-09-14 18:49:26 +0200573out:
574 return EFI_EXIT(ret);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100575}
576
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200577/**
578 * efi_cout_enable_cursor() - enable the cursor
579 *
580 * This function implements the EnableCursor service of the simple text output
581 * protocol. See the Unified Extensible Firmware Interface (UEFI) specification
582 * for details.
583 *
584 * @this: pointer to the protocol instance
585 * @enable: if true enable, if false disable the cursor
586 * Return: status code
587 */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100588static efi_status_t EFIAPI efi_cout_enable_cursor(
589 struct efi_simple_text_output_protocol *this,
590 bool enable)
591{
592 EFI_ENTRY("%p, %d", this, enable);
593
594 printf(ESC"[?25%c", enable ? 'h' : 'l');
Heinrich Schuchardt53f26b92019-06-02 22:54:28 +0200595 efi_con_mode.cursor_visible = !!enable;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100596
597 return EFI_EXIT(EFI_SUCCESS);
598}
599
Heinrich Schuchardt580c13b2017-10-26 19:25:59 +0200600struct efi_simple_text_output_protocol efi_con_out = {
Alexander Graf4aacacc2016-03-04 01:10:00 +0100601 .reset = efi_cout_reset,
602 .output_string = efi_cout_output_string,
603 .test_string = efi_cout_test_string,
604 .query_mode = efi_cout_query_mode,
605 .set_mode = efi_cout_set_mode,
606 .set_attribute = efi_cout_set_attribute,
607 .clear_screen = efi_cout_clear_screen,
608 .set_cursor_position = efi_cout_set_cursor_position,
609 .enable_cursor = efi_cout_enable_cursor,
610 .mode = (void*)&efi_con_mode,
611};
612
Heinrich Schuchardt695691e2018-09-11 22:38:12 +0200613/**
614 * struct efi_cin_notify_function - registered console input notify function
615 *
616 * @link: link to list
Heinrich Schuchardtdc305ad2019-09-05 20:37:13 +0200617 * @key: key to notify
Heinrich Schuchardt695691e2018-09-11 22:38:12 +0200618 * @function: function to call
619 */
620struct efi_cin_notify_function {
621 struct list_head link;
622 struct efi_key_data key;
623 efi_status_t (EFIAPI *function)
624 (struct efi_key_data *key_data);
625};
626
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200627static bool key_available;
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200628static struct efi_key_data next_key;
Heinrich Schuchardt695691e2018-09-11 22:38:12 +0200629static LIST_HEAD(cin_notify_functions);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100630
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200631/**
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200632 * set_shift_mask() - set shift mask
633 *
634 * @mod: Xterm shift mask
Heinrich Schuchardtdc305ad2019-09-05 20:37:13 +0200635 * @key_state: receives the state of the shift, alt, control, and logo keys
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200636 */
637void set_shift_mask(int mod, struct efi_key_state *key_state)
638{
639 key_state->key_shift_state = EFI_SHIFT_STATE_VALID;
640 if (mod) {
641 --mod;
642 if (mod & 1)
643 key_state->key_shift_state |= EFI_LEFT_SHIFT_PRESSED;
644 if (mod & 2)
645 key_state->key_shift_state |= EFI_LEFT_ALT_PRESSED;
646 if (mod & 4)
647 key_state->key_shift_state |= EFI_LEFT_CONTROL_PRESSED;
Heinrich Schuchardtfea93d62019-06-16 22:33:20 +0200648 if (!mod || (mod & 8))
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200649 key_state->key_shift_state |= EFI_LEFT_LOGO_PRESSED;
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200650 }
651}
652
653/**
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200654 * analyze_modifiers() - analyze modifiers (shift, alt, ctrl) for function keys
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200655 *
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100656 * This gets called when we have already parsed CSI.
657 *
Heinrich Schuchardtdc305ad2019-09-05 20:37:13 +0200658 * @key_state: receives the state of the shift, alt, control, and logo keys
Heinrich Schuchardt8bc44ed2020-06-04 18:40:44 +0200659 * Return: the unmodified code
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100660 */
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200661static int analyze_modifiers(struct efi_key_state *key_state)
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100662{
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200663 int c, mod = 0, ret = 0;
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100664
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200665 c = getchar();
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100666
667 if (c != ';') {
668 ret = c;
669 if (c == '~')
670 goto out;
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200671 c = getchar();
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100672 }
673 for (;;) {
674 switch (c) {
675 case '0'...'9':
676 mod *= 10;
677 mod += c - '0';
678 /* fall through */
679 case ';':
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200680 c = getchar();
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100681 break;
682 default:
683 goto out;
684 }
685 }
686out:
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200687 set_shift_mask(mod, key_state);
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100688 if (!ret)
689 ret = c;
690 return ret;
691}
692
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200693/**
694 * efi_cin_read_key() - read a key from the console input
695 *
696 * @key: - key received
697 * Return: - status code
698 */
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200699static efi_status_t efi_cin_read_key(struct efi_key_data *key)
Alexander Graf4aacacc2016-03-04 01:10:00 +0100700{
701 struct efi_input_key pressed_key = {
702 .scan_code = 0,
703 .unicode_char = 0,
704 };
Heinrich Schuchardtfc5f1a12018-09-12 00:05:32 +0200705 s32 ch;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100706
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200707 if (console_read_unicode(&ch))
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200708 return EFI_NOT_READY;
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200709
710 key->key_state.key_shift_state = EFI_SHIFT_STATE_INVALID;
711 key->key_state.key_toggle_state = EFI_TOGGLE_STATE_INVALID;
712
Heinrich Schuchardtfc5f1a12018-09-12 00:05:32 +0200713 /* We do not support multi-word codes */
714 if (ch >= 0x10000)
715 ch = '?';
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200716
717 switch (ch) {
718 case 0x1b:
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100719 /*
Heinrich Schuchardte5c93172020-12-27 14:47:50 +0100720 * If a second key is received within 10 ms, assume that we are
721 * dealing with an escape sequence. Otherwise consider this the
722 * escape key being hit. 10 ms is long enough to work fine at
723 * 1200 baud and above.
724 */
725 udelay(10000);
726 if (!tstc()) {
727 pressed_key.scan_code = 23;
728 break;
729 }
730 /*
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100731 * Xterm Control Sequences
732 * https://www.xfree86.org/4.8.0/ctlseqs.html
733 */
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200734 ch = getchar();
Alexander Graf4aacacc2016-03-04 01:10:00 +0100735 switch (ch) {
736 case cESC: /* ESC */
737 pressed_key.scan_code = 23;
738 break;
Heinrich Schuchardt46e41d02019-06-16 21:41:13 +0200739 case 'O': /* F1 - F4, End */
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200740 ch = getchar();
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200741 /* consider modifiers */
Heinrich Schuchardt46e41d02019-06-16 21:41:13 +0200742 if (ch == 'F') { /* End */
743 pressed_key.scan_code = 6;
744 break;
745 } else if (ch < 'P') {
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200746 set_shift_mask(ch - '0', &key->key_state);
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200747 ch = getchar();
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200748 }
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100749 pressed_key.scan_code = ch - 'P' + 11;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100750 break;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100751 case '[':
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200752 ch = getchar();
Alexander Graf4aacacc2016-03-04 01:10:00 +0100753 switch (ch) {
754 case 'A'...'D': /* up, down right, left */
755 pressed_key.scan_code = ch - 'A' + 1;
756 break;
757 case 'F': /* End */
758 pressed_key.scan_code = 6;
759 break;
760 case 'H': /* Home */
761 pressed_key.scan_code = 5;
762 break;
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100763 case '1':
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200764 ch = analyze_modifiers(&key->key_state);
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100765 switch (ch) {
766 case '1'...'5': /* F1 - F5 */
767 pressed_key.scan_code = ch - '1' + 11;
768 break;
Heinrich Schuchardt46e41d02019-06-16 21:41:13 +0200769 case '6'...'9': /* F5 - F8 */
770 pressed_key.scan_code = ch - '6' + 15;
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100771 break;
772 case 'A'...'D': /* up, down right, left */
773 pressed_key.scan_code = ch - 'A' + 1;
774 break;
Heinrich Schuchardt46e41d02019-06-16 21:41:13 +0200775 case 'F': /* End */
776 pressed_key.scan_code = 6;
777 break;
778 case 'H': /* Home */
779 pressed_key.scan_code = 5;
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100780 break;
Heinrich Schuchardt46e41d02019-06-16 21:41:13 +0200781 case '~': /* Home */
782 pressed_key.scan_code = 5;
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100783 break;
784 }
Alexander Graf4aacacc2016-03-04 01:10:00 +0100785 break;
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100786 case '2':
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200787 ch = analyze_modifiers(&key->key_state);
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100788 switch (ch) {
789 case '0'...'1': /* F9 - F10 */
790 pressed_key.scan_code = ch - '0' + 19;
791 break;
792 case '3'...'4': /* F11 - F12 */
793 pressed_key.scan_code = ch - '3' + 21;
794 break;
795 case '~': /* INS */
796 pressed_key.scan_code = 7;
797 break;
798 }
Alexander Graf4aacacc2016-03-04 01:10:00 +0100799 break;
800 case '3': /* DEL */
801 pressed_key.scan_code = 8;
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200802 analyze_modifiers(&key->key_state);
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100803 break;
804 case '5': /* PG UP */
805 pressed_key.scan_code = 9;
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200806 analyze_modifiers(&key->key_state);
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100807 break;
808 case '6': /* PG DOWN */
809 pressed_key.scan_code = 10;
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200810 analyze_modifiers(&key->key_state);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100811 break;
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200812 } /* [ */
Alexander Graf4aacacc2016-03-04 01:10:00 +0100813 break;
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200814 default:
815 /* ALT key */
816 set_shift_mask(3, &key->key_state);
Alexander Graf4aacacc2016-03-04 01:10:00 +0100817 }
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200818 break;
819 case 0x7f:
Alexander Graf4aacacc2016-03-04 01:10:00 +0100820 /* Backspace */
821 ch = 0x08;
822 }
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200823 if (pressed_key.scan_code) {
824 key->key_state.key_shift_state |= EFI_SHIFT_STATE_VALID;
825 } else {
Heinrich Schuchardtaa503da2018-02-19 18:53:29 +0100826 pressed_key.unicode_char = ch;
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200827
828 /*
829 * Assume left control key for control characters typically
830 * entered using the control key.
831 */
832 if (ch >= 0x01 && ch <= 0x1f) {
Heinrich Schuchardt587ae792018-09-11 22:38:09 +0200833 key->key_state.key_shift_state |=
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200834 EFI_SHIFT_STATE_VALID;
835 switch (ch) {
836 case 0x01 ... 0x07:
837 case 0x0b ... 0x0c:
838 case 0x0e ... 0x1f:
839 key->key_state.key_shift_state |=
840 EFI_LEFT_CONTROL_PRESSED;
841 }
842 }
843 }
844 key->key = pressed_key;
Alexander Graf4aacacc2016-03-04 01:10:00 +0100845
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200846 return EFI_SUCCESS;
847}
848
849/**
Heinrich Schuchardt695691e2018-09-11 22:38:12 +0200850 * efi_cin_notify() - notify registered functions
851 */
852static void efi_cin_notify(void)
853{
854 struct efi_cin_notify_function *item;
855
856 list_for_each_entry(item, &cin_notify_functions, link) {
857 bool match = true;
858
859 /* We do not support toggle states */
860 if (item->key.key.unicode_char || item->key.key.scan_code) {
861 if (item->key.key.unicode_char !=
862 next_key.key.unicode_char ||
863 item->key.key.scan_code != next_key.key.scan_code)
864 match = false;
865 }
866 if (item->key.key_state.key_shift_state &&
867 item->key.key_state.key_shift_state !=
868 next_key.key_state.key_shift_state)
869 match = false;
870
871 if (match)
872 /* We don't bother about the return code */
873 EFI_CALL(item->function(&next_key));
874 }
875}
876
877/**
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200878 * efi_cin_check() - check if keyboard input is available
879 */
880static void efi_cin_check(void)
881{
882 efi_status_t ret;
883
884 if (key_available) {
Heinrich Schuchardt7b4b8d862019-06-07 06:47:01 +0200885 efi_signal_event(efi_con_in.wait_for_key);
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200886 return;
887 }
888
889 if (tstc()) {
890 ret = efi_cin_read_key(&next_key);
891 if (ret == EFI_SUCCESS) {
892 key_available = true;
893
Heinrich Schuchardt695691e2018-09-11 22:38:12 +0200894 /* Notify registered functions */
895 efi_cin_notify();
896
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200897 /* Queue the wait for key event */
Heinrich Schuchardt695691e2018-09-11 22:38:12 +0200898 if (key_available)
Heinrich Schuchardt7b4b8d862019-06-07 06:47:01 +0200899 efi_signal_event(efi_con_in.wait_for_key);
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200900 }
901 }
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200902}
903
904/**
905 * efi_cin_empty_buffer() - empty input buffer
906 */
907static void efi_cin_empty_buffer(void)
908{
909 while (tstc())
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200910 getchar();
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200911 key_available = false;
912}
913
914/**
915 * efi_cin_reset_ex() - reset console input
916 *
917 * @this: - the extended simple text input protocol
918 * @extended_verification: - extended verification
919 *
920 * This function implements the reset service of the
921 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
922 *
923 * See the Unified Extensible Firmware Interface (UEFI) specification for
924 * details.
925 *
926 * Return: old value of the task priority level
927 */
928static efi_status_t EFIAPI efi_cin_reset_ex(
929 struct efi_simple_text_input_ex_protocol *this,
930 bool extended_verification)
931{
932 efi_status_t ret = EFI_SUCCESS;
933
934 EFI_ENTRY("%p, %d", this, extended_verification);
935
936 /* Check parameters */
937 if (!this) {
938 ret = EFI_INVALID_PARAMETER;
939 goto out;
940 }
941
942 efi_cin_empty_buffer();
943out:
944 return EFI_EXIT(ret);
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +0200945}
946
947/**
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +0200948 * efi_cin_read_key_stroke_ex() - read key stroke
949 *
950 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
951 * @key_data: key read from console
952 * Return: status code
953 *
954 * This function implements the ReadKeyStrokeEx service of the
955 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
956 *
957 * See the Unified Extensible Firmware Interface (UEFI) specification for
958 * details.
959 */
960static efi_status_t EFIAPI efi_cin_read_key_stroke_ex(
961 struct efi_simple_text_input_ex_protocol *this,
962 struct efi_key_data *key_data)
963{
964 efi_status_t ret = EFI_SUCCESS;
965
966 EFI_ENTRY("%p, %p", this, key_data);
967
968 /* Check parameters */
969 if (!this || !key_data) {
970 ret = EFI_INVALID_PARAMETER;
971 goto out;
972 }
973
974 /* We don't do interrupts, so check for timers cooperatively */
975 efi_timer_check();
976
977 /* Enable console input after ExitBootServices */
978 efi_cin_check();
979
980 if (!key_available) {
981 ret = EFI_NOT_READY;
982 goto out;
983 }
Heinrich Schuchardt00b00a12019-04-06 20:59:24 +0200984 /*
985 * CTRL+A - CTRL+Z have to be signaled as a - z.
986 * SHIFT+CTRL+A - SHIFT+CTRL+Z have to be signaled as A - Z.
987 */
988 switch (next_key.key.unicode_char) {
989 case 0x01 ... 0x07:
990 case 0x0b ... 0x0c:
991 case 0x0e ... 0x1a:
992 if (!(next_key.key_state.key_toggle_state &
993 EFI_CAPS_LOCK_ACTIVE) ^
994 !(next_key.key_state.key_shift_state &
995 (EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED)))
996 next_key.key.unicode_char += 0x40;
997 else
998 next_key.key.unicode_char += 0x60;
999 }
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001000 *key_data = next_key;
1001 key_available = false;
1002 efi_con_in.wait_for_key->is_signaled = false;
Heinrich Schuchardt00b00a12019-04-06 20:59:24 +02001003
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001004out:
1005 return EFI_EXIT(ret);
1006}
1007
1008/**
1009 * efi_cin_set_state() - set toggle key state
1010 *
1011 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
Heinrich Schuchardta41ccf92019-05-18 17:07:52 +02001012 * @key_toggle_state: pointer to key toggle state
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001013 * Return: status code
1014 *
1015 * This function implements the SetState service of the
1016 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
1017 *
1018 * See the Unified Extensible Firmware Interface (UEFI) specification for
1019 * details.
1020 */
1021static efi_status_t EFIAPI efi_cin_set_state(
1022 struct efi_simple_text_input_ex_protocol *this,
Heinrich Schuchardta41ccf92019-05-18 17:07:52 +02001023 u8 *key_toggle_state)
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001024{
Heinrich Schuchardta41ccf92019-05-18 17:07:52 +02001025 EFI_ENTRY("%p, %p", this, key_toggle_state);
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001026 /*
1027 * U-Boot supports multiple console input sources like serial and
1028 * net console for which a key toggle state cannot be set at all.
1029 *
1030 * According to the UEFI specification it is allowable to not implement
1031 * this service.
1032 */
1033 return EFI_EXIT(EFI_UNSUPPORTED);
1034}
1035
1036/**
1037 * efi_cin_register_key_notify() - register key notification function
1038 *
1039 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
1040 * @key_data: key to be notified
1041 * @key_notify_function: function to be called if the key is pressed
1042 * @notify_handle: handle for unregistering the notification
1043 * Return: status code
1044 *
1045 * This function implements the SetState service of the
1046 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
1047 *
1048 * See the Unified Extensible Firmware Interface (UEFI) specification for
1049 * details.
1050 */
1051static efi_status_t EFIAPI efi_cin_register_key_notify(
1052 struct efi_simple_text_input_ex_protocol *this,
1053 struct efi_key_data *key_data,
1054 efi_status_t (EFIAPI *key_notify_function)(
1055 struct efi_key_data *key_data),
1056 void **notify_handle)
1057{
Heinrich Schuchardt695691e2018-09-11 22:38:12 +02001058 efi_status_t ret = EFI_SUCCESS;
1059 struct efi_cin_notify_function *notify_function;
1060
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001061 EFI_ENTRY("%p, %p, %p, %p",
1062 this, key_data, key_notify_function, notify_handle);
Heinrich Schuchardt695691e2018-09-11 22:38:12 +02001063
1064 /* Check parameters */
1065 if (!this || !key_data || !key_notify_function || !notify_handle) {
1066 ret = EFI_INVALID_PARAMETER;
1067 goto out;
1068 }
1069
1070 EFI_PRINT("u+%04x, sc %04x, sh %08x, tg %02x\n",
1071 key_data->key.unicode_char,
1072 key_data->key.scan_code,
1073 key_data->key_state.key_shift_state,
1074 key_data->key_state.key_toggle_state);
1075
1076 notify_function = calloc(1, sizeof(struct efi_cin_notify_function));
1077 if (!notify_function) {
1078 ret = EFI_OUT_OF_RESOURCES;
1079 goto out;
1080 }
1081 notify_function->key = *key_data;
1082 notify_function->function = key_notify_function;
1083 list_add_tail(&notify_function->link, &cin_notify_functions);
1084 *notify_handle = notify_function;
1085out:
1086 return EFI_EXIT(ret);
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001087}
1088
1089/**
1090 * efi_cin_unregister_key_notify() - unregister key notification function
1091 *
1092 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
1093 * @notification_handle: handle received when registering
1094 * Return: status code
1095 *
1096 * This function implements the SetState service of the
1097 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
1098 *
1099 * See the Unified Extensible Firmware Interface (UEFI) specification for
1100 * details.
1101 */
1102static efi_status_t EFIAPI efi_cin_unregister_key_notify(
1103 struct efi_simple_text_input_ex_protocol *this,
1104 void *notification_handle)
1105{
Heinrich Schuchardt695691e2018-09-11 22:38:12 +02001106 efi_status_t ret = EFI_INVALID_PARAMETER;
1107 struct efi_cin_notify_function *item, *notify_function =
1108 notification_handle;
1109
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001110 EFI_ENTRY("%p, %p", this, notification_handle);
Heinrich Schuchardt695691e2018-09-11 22:38:12 +02001111
1112 /* Check parameters */
1113 if (!this || !notification_handle)
1114 goto out;
1115
1116 list_for_each_entry(item, &cin_notify_functions, link) {
1117 if (item == notify_function) {
1118 ret = EFI_SUCCESS;
1119 break;
1120 }
1121 }
1122 if (ret != EFI_SUCCESS)
1123 goto out;
1124
1125 /* Remove the notify function */
1126 list_del(&notify_function->link);
1127 free(notify_function);
1128out:
1129 return EFI_EXIT(ret);
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001130}
1131
1132
1133/**
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001134 * efi_cin_reset() - drain the input buffer
1135 *
1136 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
1137 * @extended_verification: allow for exhaustive verification
1138 * Return: status code
1139 *
1140 * This function implements the Reset service of the
1141 * EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
1142 *
1143 * See the Unified Extensible Firmware Interface (UEFI) specification for
1144 * details.
1145 */
1146static efi_status_t EFIAPI efi_cin_reset
1147 (struct efi_simple_text_input_protocol *this,
1148 bool extended_verification)
1149{
1150 efi_status_t ret = EFI_SUCCESS;
1151
1152 EFI_ENTRY("%p, %d", this, extended_verification);
1153
1154 /* Check parameters */
1155 if (!this) {
1156 ret = EFI_INVALID_PARAMETER;
1157 goto out;
1158 }
1159
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001160 efi_cin_empty_buffer();
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001161out:
1162 return EFI_EXIT(ret);
1163}
1164
1165/**
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001166 * efi_cin_read_key_stroke() - read key stroke
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001167 *
1168 * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
1169 * @key: key read from console
1170 * Return: status code
1171 *
1172 * This function implements the ReadKeyStroke service of the
1173 * EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
1174 *
1175 * See the Unified Extensible Firmware Interface (UEFI) specification for
1176 * details.
1177 */
1178static efi_status_t EFIAPI efi_cin_read_key_stroke
1179 (struct efi_simple_text_input_protocol *this,
1180 struct efi_input_key *key)
1181{
1182 efi_status_t ret = EFI_SUCCESS;
1183
1184 EFI_ENTRY("%p, %p", this, key);
1185
1186 /* Check parameters */
1187 if (!this || !key) {
1188 ret = EFI_INVALID_PARAMETER;
1189 goto out;
1190 }
1191
1192 /* We don't do interrupts, so check for timers cooperatively */
1193 efi_timer_check();
1194
1195 /* Enable console input after ExitBootServices */
1196 efi_cin_check();
1197
1198 if (!key_available) {
1199 ret = EFI_NOT_READY;
1200 goto out;
1201 }
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001202 *key = next_key.key;
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001203 key_available = false;
1204 efi_con_in.wait_for_key->is_signaled = false;
1205out:
1206 return EFI_EXIT(ret);
Alexander Graf4aacacc2016-03-04 01:10:00 +01001207}
1208
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001209static struct efi_simple_text_input_ex_protocol efi_con_in_ex = {
1210 .reset = efi_cin_reset_ex,
1211 .read_key_stroke_ex = efi_cin_read_key_stroke_ex,
1212 .wait_for_key_ex = NULL,
1213 .set_state = efi_cin_set_state,
1214 .register_key_notify = efi_cin_register_key_notify,
1215 .unregister_key_notify = efi_cin_unregister_key_notify,
1216};
1217
Heinrich Schuchardt3dabffd2018-09-08 10:20:10 +02001218struct efi_simple_text_input_protocol efi_con_in = {
Alexander Graf4aacacc2016-03-04 01:10:00 +01001219 .reset = efi_cin_reset,
1220 .read_key_stroke = efi_cin_read_key_stroke,
1221 .wait_for_key = NULL,
1222};
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001223
1224static struct efi_event *console_timer_event;
1225
Heinrich Schuchardtd8b878a2018-01-19 20:24:51 +01001226/*
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001227 * efi_console_timer_notify() - notify the console timer event
Heinrich Schuchardtd8b878a2018-01-19 20:24:51 +01001228 *
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001229 * @event: console timer event
1230 * @context: not used
Heinrich Schuchardtd8b878a2018-01-19 20:24:51 +01001231 */
xypron.glpk@gmx.de0ce42dc2017-07-20 05:26:07 +02001232static void EFIAPI efi_console_timer_notify(struct efi_event *event,
1233 void *context)
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001234{
1235 EFI_ENTRY("%p, %p", event, context);
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001236 efi_cin_check();
1237 EFI_EXIT(EFI_SUCCESS);
1238}
Heinrich Schuchardtd8b878a2018-01-19 20:24:51 +01001239
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001240/**
1241 * efi_key_notify() - notify the wait for key event
1242 *
1243 * @event: wait for key event
1244 * @context: not used
1245 */
1246static void EFIAPI efi_key_notify(struct efi_event *event, void *context)
1247{
1248 EFI_ENTRY("%p, %p", event, context);
1249 efi_cin_check();
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001250 EFI_EXIT(EFI_SUCCESS);
1251}
1252
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001253/**
1254 * efi_console_register() - install the console protocols
1255 *
1256 * This function is called from do_bootefi_exec().
Heinrich Schuchardta92e9ab2018-10-02 06:08:26 +02001257 *
1258 * Return: status code
Heinrich Schuchardt49574bc2018-09-11 22:38:05 +02001259 */
Heinrich Schuchardta92e9ab2018-10-02 06:08:26 +02001260efi_status_t efi_console_register(void)
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001261{
1262 efi_status_t r;
Heinrich Schuchardt81244ea2022-02-04 20:47:09 +01001263 struct efi_device_path *dp;
Rob Clark49f7b4b2017-07-24 10:39:01 -04001264
Heinrich Schuchardt75b4e692018-04-29 20:02:46 +02001265 /* Set up mode information */
1266 query_console_size();
1267
Heinrich Schuchardt81244ea2022-02-04 20:47:09 +01001268 /* Install protocols on root node */
1269 r = EFI_CALL(efi_install_multiple_protocol_interfaces
1270 (&efi_root,
1271 &efi_guid_text_output_protocol, &efi_con_out,
1272 &efi_guid_text_input_protocol, &efi_con_in,
1273 &efi_guid_text_input_ex_protocol, &efi_con_in_ex,
1274 NULL));
Alexander Graf36bab912018-09-04 14:59:11 +02001275
Heinrich Schuchardt81244ea2022-02-04 20:47:09 +01001276 /* Create console node and install device path protocols */
1277 if (CONFIG_IS_ENABLED(DM_SERIAL)) {
1278 dp = efi_dp_from_uart();
1279 if (!dp)
1280 goto out_of_memory;
Alexander Graf36bab912018-09-04 14:59:11 +02001281
Heinrich Schuchardt81244ea2022-02-04 20:47:09 +01001282 /* Hook UART up to the device list */
1283 efi_add_handle(&uart_obj);
Alexander Graf36bab912018-09-04 14:59:11 +02001284
Heinrich Schuchardt81244ea2022-02-04 20:47:09 +01001285 /* Install device path */
1286 r = efi_add_protocol(&uart_obj, &efi_guid_device_path, dp);
1287 if (r != EFI_SUCCESS)
1288 goto out_of_memory;
1289 }
Rob Clark49f7b4b2017-07-24 10:39:01 -04001290
Heinrich Schuchardt580c13b2017-10-26 19:25:59 +02001291 /* Create console events */
Heinrich Schuchardtbf7f1692018-02-18 15:17:52 +01001292 r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK, efi_key_notify,
1293 NULL, NULL, &efi_con_in.wait_for_key);
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001294 if (r != EFI_SUCCESS) {
1295 printf("ERROR: Failed to register WaitForKey event\n");
1296 return r;
1297 }
Heinrich Schuchardt6c4cd262018-09-11 22:38:08 +02001298 efi_con_in_ex.wait_for_key_ex = efi_con_in.wait_for_key;
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001299 r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
Heinrich Schuchardtbf7f1692018-02-18 15:17:52 +01001300 efi_console_timer_notify, NULL, NULL,
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001301 &console_timer_event);
1302 if (r != EFI_SUCCESS) {
1303 printf("ERROR: Failed to register console event\n");
1304 return r;
1305 }
1306 /* 5000 ns cycle is sufficient for 2 MBaud */
1307 r = efi_set_timer(console_timer_event, EFI_TIMER_PERIODIC, 50);
1308 if (r != EFI_SUCCESS)
1309 printf("ERROR: Failed to set console timer\n");
1310 return r;
Heinrich Schuchardt580c13b2017-10-26 19:25:59 +02001311out_of_memory:
Heinrich Schuchardt6e8eff22018-09-08 19:57:24 +02001312 printf("ERROR: Out of memory\n");
Heinrich Schuchardt580c13b2017-10-26 19:25:59 +02001313 return r;
xypron.glpk@gmx.de54c7a8e2017-07-18 20:17:22 +02001314}