uboot/lib/efi_loader/efi_console.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 *  EFI application console interface
   4 *
   5 *  Copyright (c) 2016 Alexander Graf
   6 */
   7
   8#include <common.h>
   9#include <charset.h>
  10#include <time.h>
  11#include <dm/device.h>
  12#include <efi_loader.h>
  13#include <env.h>
  14#include <stdio_dev.h>
  15#include <video_console.h>
  16
  17#define EFI_COUT_MODE_2 2
  18#define EFI_MAX_COUT_MODE 3
  19
  20struct cout_mode {
  21        unsigned long columns;
  22        unsigned long rows;
  23        int present;
  24};
  25
  26static struct cout_mode efi_cout_modes[] = {
  27        /* EFI Mode 0 is 80x25 and always present */
  28        {
  29                .columns = 80,
  30                .rows = 25,
  31                .present = 1,
  32        },
  33        /* EFI Mode 1 is always 80x50 */
  34        {
  35                .columns = 80,
  36                .rows = 50,
  37                .present = 0,
  38        },
  39        /* Value are unknown until we query the console */
  40        {
  41                .columns = 0,
  42                .rows = 0,
  43                .present = 0,
  44        },
  45};
  46
  47const efi_guid_t efi_guid_text_input_ex_protocol =
  48                        EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
  49const efi_guid_t efi_guid_text_input_protocol =
  50                        EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID;
  51const efi_guid_t efi_guid_text_output_protocol =
  52                        EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID;
  53
  54#define cESC '\x1b'
  55#define ESC "\x1b"
  56
  57/* Default to mode 0 */
  58static struct simple_text_output_mode efi_con_mode = {
  59        .max_mode = 1,
  60        .mode = 0,
  61        .attribute = 0,
  62        .cursor_column = 0,
  63        .cursor_row = 0,
  64        .cursor_visible = 1,
  65};
  66
  67static int term_get_char(s32 *c)
  68{
  69        u64 timeout;
  70
  71        /* Wait up to 100 ms for a character */
  72        timeout = timer_get_us() + 100000;
  73
  74        while (!tstc())
  75                if (timer_get_us() > timeout)
  76                        return 1;
  77
  78        *c = getc();
  79        return 0;
  80}
  81
  82/*
  83 * Receive and parse a reply from the terminal.
  84 *
  85 * @n:          array of return values
  86 * @num:        number of return values expected
  87 * @end_char:   character indicating end of terminal message
  88 * @return:     non-zero indicates error
  89 */
  90static int term_read_reply(int *n, int num, char end_char)
  91{
  92        s32 c;
  93        int i = 0;
  94
  95        if (term_get_char(&c) || c != cESC)
  96                return -1;
  97
  98        if (term_get_char(&c) || c != '[')
  99                return -1;
 100
 101        n[0] = 0;
 102        while (1) {
 103                if (!term_get_char(&c)) {
 104                        if (c == ';') {
 105                                i++;
 106                                if (i >= num)
 107                                        return -1;
 108                                n[i] = 0;
 109                                continue;
 110                        } else if (c == end_char) {
 111                                break;
 112                        } else if (c > '9' || c < '0') {
 113                                return -1;
 114                        }
 115
 116                        /* Read one more decimal position */
 117                        n[i] *= 10;
 118                        n[i] += c - '0';
 119                } else {
 120                        return -1;
 121                }
 122        }
 123        if (i != num - 1)
 124                return -1;
 125
 126        return 0;
 127}
 128
 129static efi_status_t EFIAPI efi_cout_output_string(
 130                        struct efi_simple_text_output_protocol *this,
 131                        const efi_string_t string)
 132{
 133        struct simple_text_output_mode *con = &efi_con_mode;
 134        struct cout_mode *mode = &efi_cout_modes[con->mode];
 135        char *buf, *pos;
 136        u16 *p;
 137        efi_status_t ret = EFI_SUCCESS;
 138
 139        EFI_ENTRY("%p, %p", this, string);
 140
 141        if (!this || !string) {
 142                ret = EFI_INVALID_PARAMETER;
 143                goto out;
 144        }
 145
 146        buf = malloc(utf16_utf8_strlen(string) + 1);
 147        if (!buf) {
 148                ret = EFI_OUT_OF_RESOURCES;
 149                goto out;
 150        }
 151        pos = buf;
 152        utf16_utf8_strcpy(&pos, string);
 153        fputs(stdout, buf);
 154        free(buf);
 155
 156        /*
 157         * Update the cursor position.
 158         *
 159         * The UEFI spec provides advance rules for U+0000, U+0008, U+000A,
 160         * and U000D. All other control characters are ignored. Any non-control
 161         * character increase the column by one.
 162         */
 163        for (p = string; *p; ++p) {
 164                switch (*p) {
 165                case '\b':      /* U+0008, backspace */
 166                        if (con->cursor_column)
 167                                con->cursor_column--;
 168                        break;
 169                case '\n':      /* U+000A, newline */
 170                        con->cursor_column = 0;
 171                        con->cursor_row++;
 172                        break;
 173                case '\r':      /* U+000D, carriage-return */
 174                        con->cursor_column = 0;
 175                        break;
 176                case 0xd800 ... 0xdbff:
 177                        /*
 178                         * Ignore high surrogates, we do not want to count a
 179                         * Unicode character twice.
 180                         */
 181                        break;
 182                default:
 183                        /* Exclude control codes */
 184                        if (*p > 0x1f)
 185                                con->cursor_column++;
 186                        break;
 187                }
 188                if (con->cursor_column >= mode->columns) {
 189                        con->cursor_column = 0;
 190                        con->cursor_row++;
 191                }
 192                /*
 193                 * When we exceed the row count the terminal will scroll up one
 194                 * line. We have to adjust the cursor position.
 195                 */
 196                if (con->cursor_row >= mode->rows && con->cursor_row)
 197                        con->cursor_row--;
 198        }
 199
 200out:
 201        return EFI_EXIT(ret);
 202}
 203
 204static efi_status_t EFIAPI efi_cout_test_string(
 205                        struct efi_simple_text_output_protocol *this,
 206                        const efi_string_t string)
 207{
 208        EFI_ENTRY("%p, %p", this, string);
 209        return EFI_EXIT(EFI_SUCCESS);
 210}
 211
 212static bool cout_mode_matches(struct cout_mode *mode, int rows, int cols)
 213{
 214        if (!mode->present)
 215                return false;
 216
 217        return (mode->rows == rows) && (mode->columns == cols);
 218}
 219
 220/**
 221 * query_console_serial() - query console size
 222 *
 223 * @rows:       pointer to return number of rows
 224 * @cols:       pointer to return number of columns
 225 * Returns:     0 on success
 226 */
 227static int query_console_serial(int *rows, int *cols)
 228{
 229        int ret = 0;
 230        int n[2];
 231
 232        /* Empty input buffer */
 233        while (tstc())
 234                getc();
 235
 236        /*
 237         * Not all terminals understand CSI [18t for querying the console size.
 238         * We should adhere to escape sequences documented in the console_codes
 239         * man page and the ECMA-48 standard.
 240         *
 241         * So here we follow a different approach. We position the cursor to the
 242         * bottom right and query its position. Before leaving the function we
 243         * restore the original cursor position.
 244         */
 245        printf(ESC "7"          /* Save cursor position */
 246               ESC "[r"         /* Set scrolling region to full window */
 247               ESC "[999;999H"  /* Move to bottom right corner */
 248               ESC "[6n");      /* Query cursor position */
 249
 250        /* Read {rows,cols} */
 251        if (term_read_reply(n, 2, 'R')) {
 252                ret = 1;
 253                goto out;
 254        }
 255
 256        *cols = n[1];
 257        *rows = n[0];
 258out:
 259        printf(ESC "8");        /* Restore cursor position */
 260        return ret;
 261}
 262
 263/*
 264 * Update the mode table.
 265 *
 266 * By default the only mode available is 80x25. If the console has at least 50
 267 * lines, enable mode 80x50. If we can query the console size and it is neither
 268 * 80x25 nor 80x50, set it as an additional mode.
 269 */
 270static void query_console_size(void)
 271{
 272        const char *stdout_name = env_get("stdout");
 273        int rows = 25, cols = 80;
 274
 275        if (stdout_name && !strcmp(stdout_name, "vidconsole") &&
 276            IS_ENABLED(CONFIG_DM_VIDEO)) {
 277                struct stdio_dev *stdout_dev =
 278                        stdio_get_by_name("vidconsole");
 279                struct udevice *dev = stdout_dev->priv;
 280                struct vidconsole_priv *priv =
 281                        dev_get_uclass_priv(dev);
 282                rows = priv->rows;
 283                cols = priv->cols;
 284        } else if (query_console_serial(&rows, &cols)) {
 285                return;
 286        }
 287
 288        /* Test if we can have Mode 1 */
 289        if (cols >= 80 && rows >= 50) {
 290                efi_cout_modes[1].present = 1;
 291                efi_con_mode.max_mode = 2;
 292        }
 293
 294        /*
 295         * Install our mode as mode 2 if it is different
 296         * than mode 0 or 1 and set it as the currently selected mode
 297         */
 298        if (!cout_mode_matches(&efi_cout_modes[0], rows, cols) &&
 299            !cout_mode_matches(&efi_cout_modes[1], rows, cols)) {
 300                efi_cout_modes[EFI_COUT_MODE_2].columns = cols;
 301                efi_cout_modes[EFI_COUT_MODE_2].rows = rows;
 302                efi_cout_modes[EFI_COUT_MODE_2].present = 1;
 303                efi_con_mode.max_mode = EFI_MAX_COUT_MODE;
 304                efi_con_mode.mode = EFI_COUT_MODE_2;
 305        }
 306}
 307
 308static efi_status_t EFIAPI efi_cout_query_mode(
 309                        struct efi_simple_text_output_protocol *this,
 310                        unsigned long mode_number, unsigned long *columns,
 311                        unsigned long *rows)
 312{
 313        EFI_ENTRY("%p, %ld, %p, %p", this, mode_number, columns, rows);
 314
 315        if (mode_number >= efi_con_mode.max_mode)
 316                return EFI_EXIT(EFI_UNSUPPORTED);
 317
 318        if (efi_cout_modes[mode_number].present != 1)
 319                return EFI_EXIT(EFI_UNSUPPORTED);
 320
 321        if (columns)
 322                *columns = efi_cout_modes[mode_number].columns;
 323        if (rows)
 324                *rows = efi_cout_modes[mode_number].rows;
 325
 326        return EFI_EXIT(EFI_SUCCESS);
 327}
 328
 329static const struct {
 330        unsigned int fg;
 331        unsigned int bg;
 332} color[] = {
 333        { 30, 40 },     /* 0: black */
 334        { 34, 44 },     /* 1: blue */
 335        { 32, 42 },     /* 2: green */
 336        { 36, 46 },     /* 3: cyan */
 337        { 31, 41 },     /* 4: red */
 338        { 35, 45 },     /* 5: magenta */
 339        { 33, 43 },     /* 6: brown, map to yellow as EDK2 does*/
 340        { 37, 47 },     /* 7: light gray, map to white */
 341};
 342
 343/* See EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetAttribute(). */
 344static efi_status_t EFIAPI efi_cout_set_attribute(
 345                        struct efi_simple_text_output_protocol *this,
 346                        unsigned long attribute)
 347{
 348        unsigned int bold = EFI_ATTR_BOLD(attribute);
 349        unsigned int fg = EFI_ATTR_FG(attribute);
 350        unsigned int bg = EFI_ATTR_BG(attribute);
 351
 352        EFI_ENTRY("%p, %lx", this, attribute);
 353
 354        efi_con_mode.attribute = attribute;
 355        if (attribute)
 356                printf(ESC"[%u;%u;%um", bold, color[fg].fg, color[bg].bg);
 357        else
 358                printf(ESC"[0;37;40m");
 359
 360        return EFI_EXIT(EFI_SUCCESS);
 361}
 362
 363static efi_status_t EFIAPI efi_cout_clear_screen(
 364                        struct efi_simple_text_output_protocol *this)
 365{
 366        EFI_ENTRY("%p", this);
 367
 368        printf(ESC"[2J");
 369        efi_con_mode.cursor_column = 0;
 370        efi_con_mode.cursor_row = 0;
 371
 372        return EFI_EXIT(EFI_SUCCESS);
 373}
 374
 375static efi_status_t EFIAPI efi_cout_set_mode(
 376                        struct efi_simple_text_output_protocol *this,
 377                        unsigned long mode_number)
 378{
 379        EFI_ENTRY("%p, %ld", this, mode_number);
 380
 381        if (mode_number >= efi_con_mode.max_mode)
 382                return EFI_EXIT(EFI_UNSUPPORTED);
 383
 384        if (!efi_cout_modes[mode_number].present)
 385                return EFI_EXIT(EFI_UNSUPPORTED);
 386
 387        efi_con_mode.mode = mode_number;
 388        EFI_CALL(efi_cout_clear_screen(this));
 389
 390        return EFI_EXIT(EFI_SUCCESS);
 391}
 392
 393static efi_status_t EFIAPI efi_cout_reset(
 394                        struct efi_simple_text_output_protocol *this,
 395                        char extended_verification)
 396{
 397        EFI_ENTRY("%p, %d", this, extended_verification);
 398
 399        /* Clear screen */
 400        EFI_CALL(efi_cout_clear_screen(this));
 401        /* Set default colors */
 402        efi_con_mode.attribute = 0x07;
 403        printf(ESC "[0;37;40m");
 404
 405        return EFI_EXIT(EFI_SUCCESS);
 406}
 407
 408static efi_status_t EFIAPI efi_cout_set_cursor_position(
 409                        struct efi_simple_text_output_protocol *this,
 410                        unsigned long column, unsigned long row)
 411{
 412        efi_status_t ret = EFI_SUCCESS;
 413        struct simple_text_output_mode *con = &efi_con_mode;
 414        struct cout_mode *mode = &efi_cout_modes[con->mode];
 415
 416        EFI_ENTRY("%p, %ld, %ld", this, column, row);
 417
 418        /* Check parameters */
 419        if (!this) {
 420                ret = EFI_INVALID_PARAMETER;
 421                goto out;
 422        }
 423        if (row >= mode->rows || column >= mode->columns) {
 424                ret = EFI_UNSUPPORTED;
 425                goto out;
 426        }
 427
 428        /*
 429         * Set cursor position by sending CSI H.
 430         * EFI origin is [0, 0], terminal origin is [1, 1].
 431         */
 432        printf(ESC "[%d;%dH", (int)row + 1, (int)column + 1);
 433        efi_con_mode.cursor_column = column;
 434        efi_con_mode.cursor_row = row;
 435out:
 436        return EFI_EXIT(ret);
 437}
 438
 439static efi_status_t EFIAPI efi_cout_enable_cursor(
 440                        struct efi_simple_text_output_protocol *this,
 441                        bool enable)
 442{
 443        EFI_ENTRY("%p, %d", this, enable);
 444
 445        printf(ESC"[?25%c", enable ? 'h' : 'l');
 446        efi_con_mode.cursor_visible = !!enable;
 447
 448        return EFI_EXIT(EFI_SUCCESS);
 449}
 450
 451struct efi_simple_text_output_protocol efi_con_out = {
 452        .reset = efi_cout_reset,
 453        .output_string = efi_cout_output_string,
 454        .test_string = efi_cout_test_string,
 455        .query_mode = efi_cout_query_mode,
 456        .set_mode = efi_cout_set_mode,
 457        .set_attribute = efi_cout_set_attribute,
 458        .clear_screen = efi_cout_clear_screen,
 459        .set_cursor_position = efi_cout_set_cursor_position,
 460        .enable_cursor = efi_cout_enable_cursor,
 461        .mode = (void*)&efi_con_mode,
 462};
 463
 464/**
 465 * struct efi_cin_notify_function - registered console input notify function
 466 *
 467 * @link:       link to list
 468 * @key:        key to notify
 469 * @function:   function to call
 470 */
 471struct efi_cin_notify_function {
 472        struct list_head link;
 473        struct efi_key_data key;
 474        efi_status_t (EFIAPI *function)
 475                (struct efi_key_data *key_data);
 476};
 477
 478static bool key_available;
 479static struct efi_key_data next_key;
 480static LIST_HEAD(cin_notify_functions);
 481
 482/**
 483 * set_shift_mask() - set shift mask
 484 *
 485 * @mod:        Xterm shift mask
 486 * @key_state:  receives the state of the shift, alt, control, and logo keys
 487 */
 488void set_shift_mask(int mod, struct efi_key_state *key_state)
 489{
 490        key_state->key_shift_state = EFI_SHIFT_STATE_VALID;
 491        if (mod) {
 492                --mod;
 493                if (mod & 1)
 494                        key_state->key_shift_state |= EFI_LEFT_SHIFT_PRESSED;
 495                if (mod & 2)
 496                        key_state->key_shift_state |= EFI_LEFT_ALT_PRESSED;
 497                if (mod & 4)
 498                        key_state->key_shift_state |= EFI_LEFT_CONTROL_PRESSED;
 499                if (!mod || (mod & 8))
 500                        key_state->key_shift_state |= EFI_LEFT_LOGO_PRESSED;
 501        }
 502}
 503
 504/**
 505 * analyze_modifiers() - analyze modifiers (shift, alt, ctrl) for function keys
 506 *
 507 * This gets called when we have already parsed CSI.
 508 *
 509 * @key_state:  receives the state of the shift, alt, control, and logo keys
 510 * @return:     the unmodified code
 511 */
 512static int analyze_modifiers(struct efi_key_state *key_state)
 513{
 514        int c, mod = 0, ret = 0;
 515
 516        c = getc();
 517
 518        if (c != ';') {
 519                ret = c;
 520                if (c == '~')
 521                        goto out;
 522                c = getc();
 523        }
 524        for (;;) {
 525                switch (c) {
 526                case '0'...'9':
 527                        mod *= 10;
 528                        mod += c - '0';
 529                /* fall through */
 530                case ';':
 531                        c = getc();
 532                        break;
 533                default:
 534                        goto out;
 535                }
 536        }
 537out:
 538        set_shift_mask(mod, key_state);
 539        if (!ret)
 540                ret = c;
 541        return ret;
 542}
 543
 544/**
 545 * efi_cin_read_key() - read a key from the console input
 546 *
 547 * @key:        - key received
 548 * Return:      - status code
 549 */
 550static efi_status_t efi_cin_read_key(struct efi_key_data *key)
 551{
 552        struct efi_input_key pressed_key = {
 553                .scan_code = 0,
 554                .unicode_char = 0,
 555        };
 556        s32 ch;
 557
 558        if (console_read_unicode(&ch))
 559                return EFI_NOT_READY;
 560
 561        key->key_state.key_shift_state = EFI_SHIFT_STATE_INVALID;
 562        key->key_state.key_toggle_state = EFI_TOGGLE_STATE_INVALID;
 563
 564        /* We do not support multi-word codes */
 565        if (ch >= 0x10000)
 566                ch = '?';
 567
 568        switch (ch) {
 569        case 0x1b:
 570                /*
 571                 * Xterm Control Sequences
 572                 * https://www.xfree86.org/4.8.0/ctlseqs.html
 573                 */
 574                ch = getc();
 575                switch (ch) {
 576                case cESC: /* ESC */
 577                        pressed_key.scan_code = 23;
 578                        break;
 579                case 'O': /* F1 - F4, End */
 580                        ch = getc();
 581                        /* consider modifiers */
 582                        if (ch == 'F') { /* End */
 583                                pressed_key.scan_code = 6;
 584                                break;
 585                        } else if (ch < 'P') {
 586                                set_shift_mask(ch - '0', &key->key_state);
 587                                ch = getc();
 588                        }
 589                        pressed_key.scan_code = ch - 'P' + 11;
 590                        break;
 591                case '[':
 592                        ch = getc();
 593                        switch (ch) {
 594                        case 'A'...'D': /* up, down right, left */
 595                                pressed_key.scan_code = ch - 'A' + 1;
 596                                break;
 597                        case 'F': /* End */
 598                                pressed_key.scan_code = 6;
 599                                break;
 600                        case 'H': /* Home */
 601                                pressed_key.scan_code = 5;
 602                                break;
 603                        case '1':
 604                                ch = analyze_modifiers(&key->key_state);
 605                                switch (ch) {
 606                                case '1'...'5': /* F1 - F5 */
 607                                        pressed_key.scan_code = ch - '1' + 11;
 608                                        break;
 609                                case '6'...'9': /* F5 - F8 */
 610                                        pressed_key.scan_code = ch - '6' + 15;
 611                                        break;
 612                                case 'A'...'D': /* up, down right, left */
 613                                        pressed_key.scan_code = ch - 'A' + 1;
 614                                        break;
 615                                case 'F': /* End */
 616                                        pressed_key.scan_code = 6;
 617                                        break;
 618                                case 'H': /* Home */
 619                                        pressed_key.scan_code = 5;
 620                                        break;
 621                                case '~': /* Home */
 622                                        pressed_key.scan_code = 5;
 623                                        break;
 624                                }
 625                                break;
 626                        case '2':
 627                                ch = analyze_modifiers(&key->key_state);
 628                                switch (ch) {
 629                                case '0'...'1': /* F9 - F10 */
 630                                        pressed_key.scan_code = ch - '0' + 19;
 631                                        break;
 632                                case '3'...'4': /* F11 - F12 */
 633                                        pressed_key.scan_code = ch - '3' + 21;
 634                                        break;
 635                                case '~': /* INS */
 636                                        pressed_key.scan_code = 7;
 637                                        break;
 638                                }
 639                                break;
 640                        case '3': /* DEL */
 641                                pressed_key.scan_code = 8;
 642                                analyze_modifiers(&key->key_state);
 643                                break;
 644                        case '5': /* PG UP */
 645                                pressed_key.scan_code = 9;
 646                                analyze_modifiers(&key->key_state);
 647                                break;
 648                        case '6': /* PG DOWN */
 649                                pressed_key.scan_code = 10;
 650                                analyze_modifiers(&key->key_state);
 651                                break;
 652                        } /* [ */
 653                        break;
 654                default:
 655                        /* ALT key */
 656                        set_shift_mask(3, &key->key_state);
 657                }
 658                break;
 659        case 0x7f:
 660                /* Backspace */
 661                ch = 0x08;
 662        }
 663        if (pressed_key.scan_code) {
 664                key->key_state.key_shift_state |= EFI_SHIFT_STATE_VALID;
 665        } else {
 666                pressed_key.unicode_char = ch;
 667
 668                /*
 669                 * Assume left control key for control characters typically
 670                 * entered using the control key.
 671                 */
 672                if (ch >= 0x01 && ch <= 0x1f) {
 673                        key->key_state.key_shift_state |=
 674                                        EFI_SHIFT_STATE_VALID;
 675                        switch (ch) {
 676                        case 0x01 ... 0x07:
 677                        case 0x0b ... 0x0c:
 678                        case 0x0e ... 0x1f:
 679                                key->key_state.key_shift_state |=
 680                                                EFI_LEFT_CONTROL_PRESSED;
 681                        }
 682                }
 683        }
 684        key->key = pressed_key;
 685
 686        return EFI_SUCCESS;
 687}
 688
 689/**
 690 * efi_cin_notify() - notify registered functions
 691 */
 692static void efi_cin_notify(void)
 693{
 694        struct efi_cin_notify_function *item;
 695
 696        list_for_each_entry(item, &cin_notify_functions, link) {
 697                bool match = true;
 698
 699                /* We do not support toggle states */
 700                if (item->key.key.unicode_char || item->key.key.scan_code) {
 701                        if (item->key.key.unicode_char !=
 702                            next_key.key.unicode_char ||
 703                            item->key.key.scan_code != next_key.key.scan_code)
 704                                match = false;
 705                }
 706                if (item->key.key_state.key_shift_state &&
 707                    item->key.key_state.key_shift_state !=
 708                    next_key.key_state.key_shift_state)
 709                        match = false;
 710
 711                if (match)
 712                        /* We don't bother about the return code */
 713                        EFI_CALL(item->function(&next_key));
 714        }
 715}
 716
 717/**
 718 * efi_cin_check() - check if keyboard input is available
 719 */
 720static void efi_cin_check(void)
 721{
 722        efi_status_t ret;
 723
 724        if (key_available) {
 725                efi_signal_event(efi_con_in.wait_for_key);
 726                return;
 727        }
 728
 729        if (tstc()) {
 730                ret = efi_cin_read_key(&next_key);
 731                if (ret == EFI_SUCCESS) {
 732                        key_available = true;
 733
 734                        /* Notify registered functions */
 735                        efi_cin_notify();
 736
 737                        /* Queue the wait for key event */
 738                        if (key_available)
 739                                efi_signal_event(efi_con_in.wait_for_key);
 740                }
 741        }
 742}
 743
 744/**
 745 * efi_cin_empty_buffer() - empty input buffer
 746 */
 747static void efi_cin_empty_buffer(void)
 748{
 749        while (tstc())
 750                getc();
 751        key_available = false;
 752}
 753
 754/**
 755 * efi_cin_reset_ex() - reset console input
 756 *
 757 * @this:                       - the extended simple text input protocol
 758 * @extended_verification:      - extended verification
 759 *
 760 * This function implements the reset service of the
 761 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
 762 *
 763 * See the Unified Extensible Firmware Interface (UEFI) specification for
 764 * details.
 765 *
 766 * Return: old value of the task priority level
 767 */
 768static efi_status_t EFIAPI efi_cin_reset_ex(
 769                struct efi_simple_text_input_ex_protocol *this,
 770                bool extended_verification)
 771{
 772        efi_status_t ret = EFI_SUCCESS;
 773
 774        EFI_ENTRY("%p, %d", this, extended_verification);
 775
 776        /* Check parameters */
 777        if (!this) {
 778                ret = EFI_INVALID_PARAMETER;
 779                goto out;
 780        }
 781
 782        efi_cin_empty_buffer();
 783out:
 784        return EFI_EXIT(ret);
 785}
 786
 787/**
 788 * efi_cin_read_key_stroke_ex() - read key stroke
 789 *
 790 * @this:       instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
 791 * @key_data:   key read from console
 792 * Return:      status code
 793 *
 794 * This function implements the ReadKeyStrokeEx service of the
 795 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
 796 *
 797 * See the Unified Extensible Firmware Interface (UEFI) specification for
 798 * details.
 799 */
 800static efi_status_t EFIAPI efi_cin_read_key_stroke_ex(
 801                struct efi_simple_text_input_ex_protocol *this,
 802                struct efi_key_data *key_data)
 803{
 804        efi_status_t ret = EFI_SUCCESS;
 805
 806        EFI_ENTRY("%p, %p", this, key_data);
 807
 808        /* Check parameters */
 809        if (!this || !key_data) {
 810                ret = EFI_INVALID_PARAMETER;
 811                goto out;
 812        }
 813
 814        /* We don't do interrupts, so check for timers cooperatively */
 815        efi_timer_check();
 816
 817        /* Enable console input after ExitBootServices */
 818        efi_cin_check();
 819
 820        if (!key_available) {
 821                ret = EFI_NOT_READY;
 822                goto out;
 823        }
 824        /*
 825         * CTRL+A - CTRL+Z have to be signaled as a - z.
 826         * SHIFT+CTRL+A - SHIFT+CTRL+Z have to be signaled as A - Z.
 827         */
 828        switch (next_key.key.unicode_char) {
 829        case 0x01 ... 0x07:
 830        case 0x0b ... 0x0c:
 831        case 0x0e ... 0x1a:
 832                if (!(next_key.key_state.key_toggle_state &
 833                      EFI_CAPS_LOCK_ACTIVE) ^
 834                    !(next_key.key_state.key_shift_state &
 835                      (EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED)))
 836                        next_key.key.unicode_char += 0x40;
 837                else
 838                        next_key.key.unicode_char += 0x60;
 839        }
 840        *key_data = next_key;
 841        key_available = false;
 842        efi_con_in.wait_for_key->is_signaled = false;
 843
 844out:
 845        return EFI_EXIT(ret);
 846}
 847
 848/**
 849 * efi_cin_set_state() - set toggle key state
 850 *
 851 * @this:               instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
 852 * @key_toggle_state:   pointer to key toggle state
 853 * Return:              status code
 854 *
 855 * This function implements the SetState service of the
 856 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
 857 *
 858 * See the Unified Extensible Firmware Interface (UEFI) specification for
 859 * details.
 860 */
 861static efi_status_t EFIAPI efi_cin_set_state(
 862                struct efi_simple_text_input_ex_protocol *this,
 863                u8 *key_toggle_state)
 864{
 865        EFI_ENTRY("%p, %p", this, key_toggle_state);
 866        /*
 867         * U-Boot supports multiple console input sources like serial and
 868         * net console for which a key toggle state cannot be set at all.
 869         *
 870         * According to the UEFI specification it is allowable to not implement
 871         * this service.
 872         */
 873        return EFI_EXIT(EFI_UNSUPPORTED);
 874}
 875
 876/**
 877 * efi_cin_register_key_notify() - register key notification function
 878 *
 879 * @this:                       instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
 880 * @key_data:                   key to be notified
 881 * @key_notify_function:        function to be called if the key is pressed
 882 * @notify_handle:              handle for unregistering the notification
 883 * Return:                      status code
 884 *
 885 * This function implements the SetState service of the
 886 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
 887 *
 888 * See the Unified Extensible Firmware Interface (UEFI) specification for
 889 * details.
 890 */
 891static efi_status_t EFIAPI efi_cin_register_key_notify(
 892                struct efi_simple_text_input_ex_protocol *this,
 893                struct efi_key_data *key_data,
 894                efi_status_t (EFIAPI *key_notify_function)(
 895                        struct efi_key_data *key_data),
 896                void **notify_handle)
 897{
 898        efi_status_t ret = EFI_SUCCESS;
 899        struct efi_cin_notify_function *notify_function;
 900
 901        EFI_ENTRY("%p, %p, %p, %p",
 902                  this, key_data, key_notify_function, notify_handle);
 903
 904        /* Check parameters */
 905        if (!this || !key_data || !key_notify_function || !notify_handle) {
 906                ret = EFI_INVALID_PARAMETER;
 907                goto out;
 908        }
 909
 910        EFI_PRINT("u+%04x, sc %04x, sh %08x, tg %02x\n",
 911                  key_data->key.unicode_char,
 912               key_data->key.scan_code,
 913               key_data->key_state.key_shift_state,
 914               key_data->key_state.key_toggle_state);
 915
 916        notify_function = calloc(1, sizeof(struct efi_cin_notify_function));
 917        if (!notify_function) {
 918                ret = EFI_OUT_OF_RESOURCES;
 919                goto out;
 920        }
 921        notify_function->key = *key_data;
 922        notify_function->function = key_notify_function;
 923        list_add_tail(&notify_function->link, &cin_notify_functions);
 924        *notify_handle = notify_function;
 925out:
 926        return EFI_EXIT(ret);
 927}
 928
 929/**
 930 * efi_cin_unregister_key_notify() - unregister key notification function
 931 *
 932 * @this:                       instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
 933 * @notification_handle:        handle received when registering
 934 * Return:                      status code
 935 *
 936 * This function implements the SetState service of the
 937 * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
 938 *
 939 * See the Unified Extensible Firmware Interface (UEFI) specification for
 940 * details.
 941 */
 942static efi_status_t EFIAPI efi_cin_unregister_key_notify(
 943                struct efi_simple_text_input_ex_protocol *this,
 944                void *notification_handle)
 945{
 946        efi_status_t ret = EFI_INVALID_PARAMETER;
 947        struct efi_cin_notify_function *item, *notify_function =
 948                        notification_handle;
 949
 950        EFI_ENTRY("%p, %p", this, notification_handle);
 951
 952        /* Check parameters */
 953        if (!this || !notification_handle)
 954                goto out;
 955
 956        list_for_each_entry(item, &cin_notify_functions, link) {
 957                if (item == notify_function) {
 958                        ret = EFI_SUCCESS;
 959                        break;
 960                }
 961        }
 962        if (ret != EFI_SUCCESS)
 963                goto out;
 964
 965        /* Remove the notify function */
 966        list_del(&notify_function->link);
 967        free(notify_function);
 968out:
 969        return EFI_EXIT(ret);
 970}
 971
 972
 973/**
 974 * efi_cin_reset() - drain the input buffer
 975 *
 976 * @this:                       instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
 977 * @extended_verification:      allow for exhaustive verification
 978 * Return:                      status code
 979 *
 980 * This function implements the Reset service of the
 981 * EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
 982 *
 983 * See the Unified Extensible Firmware Interface (UEFI) specification for
 984 * details.
 985 */
 986static efi_status_t EFIAPI efi_cin_reset
 987                        (struct efi_simple_text_input_protocol *this,
 988                         bool extended_verification)
 989{
 990        efi_status_t ret = EFI_SUCCESS;
 991
 992        EFI_ENTRY("%p, %d", this, extended_verification);
 993
 994        /* Check parameters */
 995        if (!this) {
 996                ret = EFI_INVALID_PARAMETER;
 997                goto out;
 998        }
 999
1000        efi_cin_empty_buffer();
1001out:
1002        return EFI_EXIT(ret);
1003}
1004
1005/**
1006 * efi_cin_read_key_stroke() - read key stroke
1007 *
1008 * @this:       instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
1009 * @key:        key read from console
1010 * Return:      status code
1011 *
1012 * This function implements the ReadKeyStroke service of the
1013 * EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
1014 *
1015 * See the Unified Extensible Firmware Interface (UEFI) specification for
1016 * details.
1017 */
1018static efi_status_t EFIAPI efi_cin_read_key_stroke
1019                        (struct efi_simple_text_input_protocol *this,
1020                         struct efi_input_key *key)
1021{
1022        efi_status_t ret = EFI_SUCCESS;
1023
1024        EFI_ENTRY("%p, %p", this, key);
1025
1026        /* Check parameters */
1027        if (!this || !key) {
1028                ret = EFI_INVALID_PARAMETER;
1029                goto out;
1030        }
1031
1032        /* We don't do interrupts, so check for timers cooperatively */
1033        efi_timer_check();
1034
1035        /* Enable console input after ExitBootServices */
1036        efi_cin_check();
1037
1038        if (!key_available) {
1039                ret = EFI_NOT_READY;
1040                goto out;
1041        }
1042        *key = next_key.key;
1043        key_available = false;
1044        efi_con_in.wait_for_key->is_signaled = false;
1045out:
1046        return EFI_EXIT(ret);
1047}
1048
1049static struct efi_simple_text_input_ex_protocol efi_con_in_ex = {
1050        .reset = efi_cin_reset_ex,
1051        .read_key_stroke_ex = efi_cin_read_key_stroke_ex,
1052        .wait_for_key_ex = NULL,
1053        .set_state = efi_cin_set_state,
1054        .register_key_notify = efi_cin_register_key_notify,
1055        .unregister_key_notify = efi_cin_unregister_key_notify,
1056};
1057
1058struct efi_simple_text_input_protocol efi_con_in = {
1059        .reset = efi_cin_reset,
1060        .read_key_stroke = efi_cin_read_key_stroke,
1061        .wait_for_key = NULL,
1062};
1063
1064static struct efi_event *console_timer_event;
1065
1066/*
1067 * efi_console_timer_notify() - notify the console timer event
1068 *
1069 * @event:      console timer event
1070 * @context:    not used
1071 */
1072static void EFIAPI efi_console_timer_notify(struct efi_event *event,
1073                                            void *context)
1074{
1075        EFI_ENTRY("%p, %p", event, context);
1076        efi_cin_check();
1077        EFI_EXIT(EFI_SUCCESS);
1078}
1079
1080/**
1081 * efi_key_notify() - notify the wait for key event
1082 *
1083 * @event:      wait for key event
1084 * @context:    not used
1085 */
1086static void EFIAPI efi_key_notify(struct efi_event *event, void *context)
1087{
1088        EFI_ENTRY("%p, %p", event, context);
1089        efi_cin_check();
1090        EFI_EXIT(EFI_SUCCESS);
1091}
1092
1093/**
1094 * efi_console_register() - install the console protocols
1095 *
1096 * This function is called from do_bootefi_exec().
1097 *
1098 * Return:      status code
1099 */
1100efi_status_t efi_console_register(void)
1101{
1102        efi_status_t r;
1103        efi_handle_t console_output_handle;
1104        efi_handle_t console_input_handle;
1105
1106        /* Set up mode information */
1107        query_console_size();
1108
1109        /* Create handles */
1110        r = efi_create_handle(&console_output_handle);
1111        if (r != EFI_SUCCESS)
1112                goto out_of_memory;
1113
1114        r = efi_add_protocol(console_output_handle,
1115                             &efi_guid_text_output_protocol, &efi_con_out);
1116        if (r != EFI_SUCCESS)
1117                goto out_of_memory;
1118        systab.con_out_handle = console_output_handle;
1119        systab.stderr_handle = console_output_handle;
1120
1121        r = efi_create_handle(&console_input_handle);
1122        if (r != EFI_SUCCESS)
1123                goto out_of_memory;
1124
1125        r = efi_add_protocol(console_input_handle,
1126                             &efi_guid_text_input_protocol, &efi_con_in);
1127        if (r != EFI_SUCCESS)
1128                goto out_of_memory;
1129        systab.con_in_handle = console_input_handle;
1130        r = efi_add_protocol(console_input_handle,
1131                             &efi_guid_text_input_ex_protocol, &efi_con_in_ex);
1132        if (r != EFI_SUCCESS)
1133                goto out_of_memory;
1134
1135        /* Create console events */
1136        r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK, efi_key_notify,
1137                             NULL, NULL, &efi_con_in.wait_for_key);
1138        if (r != EFI_SUCCESS) {
1139                printf("ERROR: Failed to register WaitForKey event\n");
1140                return r;
1141        }
1142        efi_con_in_ex.wait_for_key_ex = efi_con_in.wait_for_key;
1143        r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
1144                             efi_console_timer_notify, NULL, NULL,
1145                             &console_timer_event);
1146        if (r != EFI_SUCCESS) {
1147                printf("ERROR: Failed to register console event\n");
1148                return r;
1149        }
1150        /* 5000 ns cycle is sufficient for 2 MBaud */
1151        r = efi_set_timer(console_timer_event, EFI_TIMER_PERIODIC, 50);
1152        if (r != EFI_SUCCESS)
1153                printf("ERROR: Failed to set console timer\n");
1154        return r;
1155out_of_memory:
1156        printf("ERROR: Out of memory\n");
1157        return r;
1158}
1159