2 * Copyright (c) 2000 Doug Rabson
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
34 #include <sys/reboot.h>
35 #include <machine/metadata.h>
37 #include <framebuffer.h>
38 #include "bootstrap.h"
40 extern EFI_GUID gop_guid;
41 static EFI_GUID simple_input_ex_guid = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
42 static SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
43 static SIMPLE_INPUT_INTERFACE *conin;
44 static EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *coninex;
45 static bool efi_started;
47 static int mode; /* Does ConOut have serial console? */
49 static uint32_t utf8_left;
50 static uint32_t utf8_partial;
52 #define DEFAULT_FGCOLOR EFI_LIGHTGRAY
53 #define DEFAULT_BGCOLOR EFI_BLACK
56 static int args[MAXARGS], argc;
57 static int fg_c, bg_c, curx, cury;
60 void get_pos(int *x, int *y);
61 void curs_move(int *_x, int *_y, int x, int y);
70 static tf_bell_t efi_cons_bell;
71 static tf_cursor_t efi_text_cursor;
72 static tf_putchar_t efi_text_putchar;
73 static tf_fill_t efi_text_fill;
74 static tf_copy_t efi_text_copy;
75 static tf_param_t efi_text_param;
76 static tf_respond_t efi_cons_respond;
78 static teken_funcs_t tf = {
79 .tf_bell = efi_cons_bell,
80 .tf_cursor = efi_text_cursor,
81 .tf_putchar = efi_text_putchar,
82 .tf_fill = efi_text_fill,
83 .tf_copy = efi_text_copy,
84 .tf_param = efi_text_param,
85 .tf_respond = efi_cons_respond,
88 static teken_funcs_t tfx = {
89 .tf_bell = efi_cons_bell,
90 .tf_cursor = gfx_fb_cursor,
91 .tf_putchar = gfx_fb_putchar,
92 .tf_fill = gfx_fb_fill,
93 .tf_copy = gfx_fb_copy,
94 .tf_param = gfx_fb_param,
95 .tf_respond = efi_cons_respond,
99 static unsigned keybuf[KEYBUFSZ]; /* keybuf for extended codes */
100 static int key_pending;
102 static const unsigned char teken_color_to_efi_color[16] = {
121 static void efi_cons_probe(struct console *);
122 static int efi_cons_init(int);
123 void efi_cons_putchar(int);
124 int efi_cons_getchar(void);
125 void efi_cons_efiputchar(int);
126 int efi_cons_poll(void);
127 static void cons_draw_frame(teken_attr_t *);
129 struct console efi_console = {
141 * This function is used to mark a rectangular image area so the scrolling
142 * will know we need to copy the data from there.
145 term_image_display(teken_gfx_t *state, const teken_rect_t *r)
150 if (screen_buffer == NULL)
153 for (p.tp_row = r->tr_begin.tp_row;
154 p.tp_row < r->tr_end.tp_row; p.tp_row++) {
155 for (p.tp_col = r->tr_begin.tp_col;
156 p.tp_col < r->tr_end.tp_col; p.tp_col++) {
157 idx = p.tp_col + p.tp_row * state->tg_tp.tp_col;
158 if (idx >= state->tg_tp.tp_col * state->tg_tp.tp_row)
160 screen_buffer[idx].a.ta_format |= TF_IMAGE;
169 efi_cons_bell(void *s __unused)
174 efi_text_cursor(void *arg, const teken_pos_t *p)
176 teken_gfx_t *state = arg;
180 if (p->tp_row >= state->tg_tp.tp_row)
181 row = state->tg_tp.tp_row - 1;
184 if (p->tp_col >= state->tg_tp.tp_col)
185 col = state->tg_tp.tp_col - 1;
187 conout->SetCursorPosition(conout, col, row);
191 efi_text_printchar(teken_gfx_t *state, const teken_pos_t *p, bool autoscroll)
194 struct text_pixel *px;
195 teken_color_t fg, bg, tmp;
197 px = screen_buffer + p->tp_col + p->tp_row * state->tg_tp.tp_col;
198 a = conout->Mode->Attribute;
200 fg = teken_256to16(px->a.ta_fgcolor);
201 bg = teken_256to16(px->a.ta_bgcolor);
202 if (px->a.ta_format & TF_BOLD)
204 if (px->a.ta_format & TF_BLINK)
207 if (px->a.ta_format & TF_REVERSE) {
213 attr = EFI_TEXT_ATTR(teken_color_to_efi_color[fg],
214 teken_color_to_efi_color[bg] & 0x7);
216 conout->SetCursorPosition(conout, p->tp_col, p->tp_row);
218 /* to prevent autoscroll, skip print of lower right char */
220 p->tp_row == state->tg_tp.tp_row - 1 &&
221 p->tp_col == state->tg_tp.tp_col - 1)
224 (void) conout->SetAttribute(conout, attr);
225 efi_cons_efiputchar(px->c);
226 (void) conout->SetAttribute(conout, a);
230 efi_text_putchar(void *s, const teken_pos_t *p, teken_char_t c,
231 const teken_attr_t *a)
233 teken_gfx_t *state = s;
237 idx = p->tp_col + p->tp_row * state->tg_tp.tp_col;
238 if (idx >= state->tg_tp.tp_col * state->tg_tp.tp_row)
241 screen_buffer[idx].c = c;
242 screen_buffer[idx].a = *a;
244 efi_text_printchar(s, p, false);
248 efi_text_fill(void *arg, const teken_rect_t *r, teken_char_t c,
249 const teken_attr_t *a)
251 teken_gfx_t *state = arg;
254 if (state->tg_cursor_visible)
255 conout->EnableCursor(conout, FALSE);
256 for (p.tp_row = r->tr_begin.tp_row; p.tp_row < r->tr_end.tp_row;
258 for (p.tp_col = r->tr_begin.tp_col;
259 p.tp_col < r->tr_end.tp_col; p.tp_col++)
260 efi_text_putchar(state, &p, c, a);
261 if (state->tg_cursor_visible)
262 conout->EnableCursor(conout, TRUE);
266 efi_text_copy_line(teken_gfx_t *state, int ncol, teken_pos_t *s,
267 teken_pos_t *d, bool scroll)
269 unsigned soffset, doffset;
273 soffset = s->tp_col + s->tp_row * state->tg_tp.tp_col;
274 doffset = d->tp_col + d->tp_row * state->tg_tp.tp_col;
278 for (x = 0; x < ncol; x++) {
279 sp.tp_col = s->tp_col + x;
280 dp.tp_col = d->tp_col + x;
281 if (!is_same_pixel(&screen_buffer[soffset + x],
282 &screen_buffer[doffset + x])) {
283 screen_buffer[doffset + x] =
284 screen_buffer[soffset + x];
286 efi_text_printchar(state, &dp, false);
288 /* Draw last char and trigger scroll. */
289 if (dp.tp_col + 1 == state->tg_tp.tp_col &&
290 dp.tp_row + 1 == state->tg_tp.tp_row) {
291 efi_text_printchar(state, &dp, true);
298 efi_text_copy(void *arg, const teken_rect_t *r, const teken_pos_t *p)
300 teken_gfx_t *state = arg;
301 unsigned doffset, soffset;
303 int nrow, ncol, x, y; /* Has to be signed - >= 0 comparison */
307 * Copying is a little tricky. We must make sure we do it in
308 * correct order, to make sure we don't overwrite our own data.
311 nrow = r->tr_end.tp_row - r->tr_begin.tp_row;
312 ncol = r->tr_end.tp_col - r->tr_begin.tp_col;
315 * Check if we do copy whole screen.
317 if (p->tp_row == 0 && p->tp_col == 0 &&
318 nrow == state->tg_tp.tp_row - 2 && ncol == state->tg_tp.tp_col - 2)
321 soffset = r->tr_begin.tp_col + r->tr_begin.tp_row * state->tg_tp.tp_col;
322 doffset = p->tp_col + p->tp_row * state->tg_tp.tp_col;
324 /* remove the cursor */
325 if (state->tg_cursor_visible)
326 conout->EnableCursor(conout, FALSE);
331 if (doffset <= soffset) {
334 for (y = 0; y < nrow; y++) {
335 s.tp_row = r->tr_begin.tp_row + y;
336 d.tp_row = p->tp_row + y;
338 efi_text_copy_line(state, ncol, &s, &d, scroll);
341 for (y = nrow - 1; y >= 0; y--) {
342 s.tp_row = r->tr_begin.tp_row + y;
343 d.tp_row = p->tp_row + y;
345 efi_text_copy_line(state, ncol, &s, &d, false);
349 /* display the cursor */
350 if (state->tg_cursor_visible)
351 conout->EnableCursor(conout, TRUE);
355 efi_text_param(void *arg, int cmd, unsigned int value)
357 teken_gfx_t *state = arg;
360 case TP_SETLOCALCURSOR:
362 * 0 means normal (usually block), 1 means hidden, and
363 * 2 means blinking (always block) for compatibility with
364 * syscons. We don't support any changes except hiding,
365 * so must map 2 to 0.
367 value = (value == 1) ? 0 : 1;
371 conout->EnableCursor(conout, TRUE);
372 state->tg_cursor_visible = true;
374 conout->EnableCursor(conout, FALSE);
375 state->tg_cursor_visible = false;
379 /* Not yet implemented */
388 efi_cons_respond(void *s __unused, const void *buf __unused,
394 * Set up conin/conout/coninex to make sure we have input ready.
397 efi_cons_probe(struct console *cp)
405 * Call SetMode to work around buggy firmware.
407 status = conout->SetMode(conout, conout->Mode->Mode);
409 if (coninex == NULL) {
410 status = BS->OpenProtocol(ST->ConsoleInHandle,
411 &simple_input_ex_guid, (void **)&coninex,
412 IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
413 if (status != EFI_SUCCESS)
417 cp->c_flags |= C_PRESENTIN | C_PRESENTOUT;
421 color_name_to_teken(const char *name, int *val)
423 if (strcasecmp(name, "black") == 0) {
427 if (strcasecmp(name, "red") == 0) {
431 if (strcasecmp(name, "green") == 0) {
435 if (strcasecmp(name, "brown") == 0) {
439 if (strcasecmp(name, "blue") == 0) {
443 if (strcasecmp(name, "magenta") == 0) {
447 if (strcasecmp(name, "cyan") == 0) {
451 if (strcasecmp(name, "white") == 0) {
459 efi_set_colors(struct env_var *ev, int flags, const void *value)
464 const teken_attr_t *ap;
470 if (color_name_to_teken(value, &val)) {
471 snprintf(buf, sizeof (buf), "%d", val);
477 val = (int)strtol(value, &end, 0);
478 if (errno != 0 || *end != '\0') {
479 printf("Allowed values are either ansi color name or "
480 "number from range [0-7].\n");
486 ap = teken_get_defattr(&gfx_state.tg_teken);
488 if (strcmp(ev->ev_name, "teken.fg_color") == 0) {
489 /* is it already set? */
490 if (ap->ta_fgcolor == val)
494 if (strcmp(ev->ev_name, "teken.bg_color") == 0) {
495 /* is it already set? */
496 if (ap->ta_bgcolor == val)
501 /* Improve visibility */
502 if (a.ta_bgcolor == TC_WHITE)
503 a.ta_bgcolor |= TC_LIGHT;
505 teken_set_defattr(&gfx_state.tg_teken, &a);
507 env_setenv(ev->ev_name, flags | EV_NOHOOK, evalue, NULL, NULL);
508 teken_input(&gfx_state.tg_teken, "\e[2J", 4);
513 /* Get cursor position. */
515 get_pos(int *x, int *y)
517 *x = conout->Mode->CursorColumn;
518 *y = conout->Mode->CursorRow;
521 /* Move cursor to x rows and y cols (0-based). */
523 curs_move(int *_x, int *_y, int x, int y)
525 conout->SetCursorPosition(conout, x, y);
527 *_x = conout->Mode->CursorColumn;
529 *_y = conout->Mode->CursorRow;
532 /* Clear internal state of the terminal emulation code. */
542 efi_cons_rawputchar(int c)
546 conout->QueryMode(conout, conout->Mode->Mode, &x, &y);
551 n = 8 - ((conout->Mode->CursorColumn + 8) % 8);
552 for (i = 0; i < n; i++)
553 efi_cons_rawputchar(' ');
557 efi_cons_efiputchar('\r');
558 efi_cons_efiputchar(c);
563 efi_cons_efiputchar('\r');
566 efi_cons_efiputchar('\n');
567 efi_cons_efiputchar('\r');
575 efi_cons_efiputchar('\b');
580 efi_cons_efiputchar(c);
593 conout->EnableCursor(conout, TRUE);
597 /* Gracefully exit ESC-sequence processing in case of misunderstanding. */
605 efi_cons_rawputchar('\033');
607 efi_cons_rawputchar(esc);
608 for (i = 0; i <= argc; ++i) {
609 sprintf(buf, "%d", args[i]);
612 efi_cons_rawputchar(*ch++);
615 efi_cons_rawputchar(c);
619 /* Clear display from current position to end of screen. */
626 get_pos(&curx, &cury);
627 if (curx == 0 && cury == 0) {
628 conout->ClearScreen(conout);
633 conout->QueryMode(conout, conout->Mode->Mode, &x, &y);
634 CL(0); /* clear current line from cursor to end */
635 for (i = cury + 1; i < y-1; i++) {
636 curs_move(NULL, NULL, 0, i);
639 curs_move(NULL, NULL, curx, cury);
644 * Absolute cursor move to args[0] rows and args[1] columns
645 * (the coordinates are 1-based).
654 curs_move(&curx, &cury, args[1], args[0]);
658 /* Home cursor (left top corner), also called from mode command. */
663 args[0] = args[1] = 1;
667 /* Clear line from current position to end of line */
675 conout->QueryMode(conout, conout->Mode->Mode, &x, &y);
677 case 0: /* from cursor to end */
680 case 1: /* from beginning to cursor */
683 case 2: /* entire line */
686 default: /* NOTREACHED */
693 line = malloc(len * sizeof (CHAR16));
695 printf("out of memory\n");
698 for (i = 0; i < len; i++)
703 curs_move(NULL, NULL, 0, cury);
705 conout->OutputString(conout, line);
706 /* restore cursor position */
707 curs_move(NULL, NULL, curx, cury);
718 args[argc] += c - '0';
722 /* Emulate basic capabilities of cons25 terminal */
727 static int ansi_col[] = {
728 0, 4, 2, 6, 1, 5, 3, 7
740 efi_cons_rawputchar(c);
761 else if (argc + 1 >= MAXARGS)
766 case 'H': /* ho = \E[H */
774 case 'J': /* cd = \E[J */
782 fg_c = DEFAULT_FGCOLOR;
783 bg_c = DEFAULT_BGCOLOR;
785 for (i = 0; i <= argc; ++i) {
787 case 0: /* back to normal */
788 fg_c = DEFAULT_FGCOLOR;
789 bg_c = DEFAULT_BGCOLOR;
794 case 4: /* underline */
798 case 7: /* reverse */
803 case 22: /* normal intensity */
806 case 24: /* not underline */
807 case 25: /* not blinking */
810 case 30: case 31: case 32: case 33:
811 case 34: case 35: case 36: case 37:
812 fg_c = ansi_col[args[i] - 30];
814 case 39: /* normal */
815 fg_c = DEFAULT_FGCOLOR;
817 case 40: case 41: case 42: case 43:
818 case 44: case 45: case 46: case 47:
819 bg_c = ansi_col[args[i] - 40];
821 case 49: /* normal */
822 bg_c = DEFAULT_BGCOLOR;
826 conout->SetAttribute(conout, EFI_TEXT_ATTR(fg_c, bg_c));
842 efi_cons_rawputchar(c);
847 env_screen_nounset(struct env_var *ev __unused)
849 if (gfx_state.tg_fb_type == FB_TEXT)
855 cons_draw_frame(teken_attr_t *a)
857 teken_attr_t attr = *a;
858 teken_color_t fg = a->ta_fgcolor;
860 attr.ta_fgcolor = attr.ta_bgcolor;
861 teken_set_defattr(&gfx_state.tg_teken, &attr);
863 gfx_fb_drawrect(0, 0, gfx_state.tg_fb.fb_width,
864 gfx_state.tg_origin.tp_row, 1);
866 gfx_state.tg_fb.fb_height - gfx_state.tg_origin.tp_row - 1,
867 gfx_state.tg_fb.fb_width, gfx_state.tg_fb.fb_height, 1);
868 gfx_fb_drawrect(0, gfx_state.tg_origin.tp_row,
869 gfx_state.tg_origin.tp_col,
870 gfx_state.tg_fb.fb_height - gfx_state.tg_origin.tp_row - 1, 1);
872 gfx_state.tg_fb.fb_width - gfx_state.tg_origin.tp_col - 1,
873 gfx_state.tg_origin.tp_row, gfx_state.tg_fb.fb_width,
874 gfx_state.tg_fb.fb_height, 1);
876 attr.ta_fgcolor = fg;
877 teken_set_defattr(&gfx_state.tg_teken, &attr);
881 cons_update_mode(bool use_gfx_mode)
884 const teken_attr_t *a;
893 * Despite the use_gfx_mode, we want to make sure we call
894 * efi_find_framebuffer(). This will populate the fb data,
895 * which will be passed to kernel.
897 if (efi_find_framebuffer(&gfx_state) == 0 && use_gfx_mode) {
898 int roff, goff, boff;
900 roff = ffs(gfx_state.tg_fb.fb_mask_red) - 1;
901 goff = ffs(gfx_state.tg_fb.fb_mask_green) - 1;
902 boff = ffs(gfx_state.tg_fb.fb_mask_blue) - 1;
904 (void) generate_cons_palette(cmap, COLOR_FORMAT_RGB,
905 gfx_state.tg_fb.fb_mask_red >> roff, roff,
906 gfx_state.tg_fb.fb_mask_green >> goff, goff,
907 gfx_state.tg_fb.fb_mask_blue >> boff, boff);
910 * Either text mode was asked by user or we failed to
913 gfx_state.tg_fb_type = FB_TEXT;
916 status = conout->QueryMode(conout, conout->Mode->Mode, &cols, &rows);
917 if (EFI_ERROR(status) || cols * rows == 0) {
923 * When we have serial port listed in ConOut, use pre-teken emulator,
925 * The problem is, we can not output text on efi and comconsole when
926 * efi also has comconsole bound. But then again, we need to have
927 * terminal emulator for efi text mode to support the menu.
928 * While teken is too expensive to be used on serial console, the
929 * pre-teken emulator is light enough to be used on serial console.
931 * When doing multiple consoles (both serial and video),
932 * also just use the old emulator. RB_MULTIPLE also implies
933 * we're using a serial console.
935 mode = parse_uefi_con_out();
936 if ((mode & (RB_SERIAL | RB_MULTIPLE)) == 0) {
937 conout->EnableCursor(conout, FALSE);
938 gfx_state.tg_cursor_visible = false;
940 if (gfx_state.tg_fb_type == FB_TEXT) {
942 gfx_state.tg_functions = &tf;
943 /* ensure the following are not set for text mode */
944 unsetenv("screen.height");
945 unsetenv("screen.width");
946 unsetenv("screen.depth");
948 uint32_t fb_height, fb_width;
950 fb_height = gfx_state.tg_fb.fb_height;
951 fb_width = gfx_state.tg_fb.fb_width;
954 * setup_font() can adjust terminal size.
955 * We can see two kind of bad happening.
956 * We either can get too small console font - requested
957 * terminal size is large, display resolution is
958 * large, and we get very small font.
959 * Or, we can get too large font - requested
960 * terminal size is small and this will cause large
961 * font to be selected.
962 * Now, the setup_font() is updated to consider
963 * display density and this should give us mostly
964 * acceptable font. However, the catch is, not all
965 * display devices will give us display density.
966 * Still, we do hope, external monitors do - this is
967 * where the display size will matter the most.
968 * And for laptop screens, we should still get good
969 * results by requesting 80x25 terminal.
971 gfx_state.tg_tp.tp_row = 25;
972 gfx_state.tg_tp.tp_col = 80;
973 setup_font(&gfx_state, fb_height, fb_width);
974 rows = gfx_state.tg_tp.tp_row;
975 cols = gfx_state.tg_tp.tp_col;
976 /* Point of origin in pixels. */
977 gfx_state.tg_origin.tp_row = (fb_height -
978 (rows * gfx_state.tg_font.vf_height)) / 2;
979 gfx_state.tg_origin.tp_col = (fb_width -
980 (cols * gfx_state.tg_font.vf_width)) / 2;
982 /* UEFI gop has depth 32. */
983 gfx_state.tg_glyph_size = gfx_state.tg_font.vf_height *
984 gfx_state.tg_font.vf_width * 4;
985 free(gfx_state.tg_glyph);
986 gfx_state.tg_glyph = malloc(gfx_state.tg_glyph_size);
987 if (gfx_state.tg_glyph == NULL)
990 gfx_state.tg_functions = &tfx;
991 snprintf(env, sizeof (env), "%d", fb_height);
992 env_setenv("screen.height", EV_VOLATILE | EV_NOHOOK,
993 env, env_noset, env_screen_nounset);
994 snprintf(env, sizeof (env), "%d", fb_width);
995 env_setenv("screen.width", EV_VOLATILE | EV_NOHOOK,
996 env, env_noset, env_screen_nounset);
997 snprintf(env, sizeof (env), "%d",
998 gfx_state.tg_fb.fb_bpp);
999 env_setenv("screen.depth", EV_VOLATILE | EV_NOHOOK,
1000 env, env_noset, env_screen_nounset);
1003 /* Record our terminal screen size. */
1004 gfx_state.tg_tp.tp_row = rows;
1005 gfx_state.tg_tp.tp_col = cols;
1007 teken_init(&gfx_state.tg_teken, gfx_state.tg_functions,
1010 free(screen_buffer);
1011 screen_buffer = malloc(rows * cols * sizeof(*screen_buffer));
1012 if (screen_buffer != NULL) {
1013 teken_set_winsize(&gfx_state.tg_teken,
1015 a = teken_get_defattr(&gfx_state.tg_teken);
1019 * On first run, we set up the efi_set_colors()
1020 * callback. If the env is already set, we
1021 * pick up fg and bg color values from the environment.
1023 ptr = getenv("teken.fg_color");
1025 attr.ta_fgcolor = strtol(ptr, NULL, 10);
1026 ptr = getenv("teken.bg_color");
1027 attr.ta_bgcolor = strtol(ptr, NULL, 10);
1029 teken_set_defattr(&gfx_state.tg_teken, &attr);
1031 snprintf(env, sizeof(env), "%d",
1033 env_setenv("teken.fg_color", EV_VOLATILE, env,
1034 efi_set_colors, env_nounset);
1035 snprintf(env, sizeof(env), "%d",
1037 env_setenv("teken.bg_color", EV_VOLATILE, env,
1038 efi_set_colors, env_nounset);
1043 if (screen_buffer == NULL) {
1044 conout->EnableCursor(conout, TRUE);
1046 conout->SetAttribute(conout, EFI_TEXT_ATTR(DEFAULT_FGCOLOR,
1049 get_pos(&curx, &cury);
1050 curs_move(&curx, &cury, curx, cury);
1051 fg_c = DEFAULT_FGCOLOR;
1052 bg_c = DEFAULT_BGCOLOR;
1055 /* Improve visibility */
1056 if (attr.ta_bgcolor == TC_WHITE)
1057 attr.ta_bgcolor |= TC_LIGHT;
1058 teken_set_defattr(&gfx_state.tg_teken, &attr);
1060 /* Draw frame around terminal area. */
1061 cons_draw_frame(&attr);
1063 * Erase display, this will also fill our screen
1066 teken_input(&gfx_state.tg_teken, "\e[2J", 4);
1067 gfx_state.tg_functions->tf_param(&gfx_state,
1071 snprintf(env, sizeof (env), "%u", (unsigned)rows);
1072 setenv("LINES", env, 1);
1073 snprintf(env, sizeof (env), "%u", (unsigned)cols);
1074 setenv("COLUMNS", env, 1);
1080 efi_cons_init(int arg)
1089 gfx_framework_init();
1090 if (cons_update_mode(gfx_state.tg_fb_type != FB_TEXT))
1105 for (i = 0; i < sizeof(utf8_partial); i++) {
1106 c = (utf8_partial >> (24 - (i << 3))) & 0xff;
1115 input_byte(uint8_t c)
1117 if ((c & 0x80) == 0x00) {
1118 /* One-byte sequence. */
1123 if ((c & 0xe0) == 0xc0) {
1124 /* Two-byte sequence. */
1130 if ((c & 0xf0) == 0xe0) {
1131 /* Three-byte sequence. */
1137 if ((c & 0xf8) == 0xf0) {
1138 /* Four-byte sequence. */
1144 if ((c & 0xc0) == 0x80) {
1145 /* Invalid state? */
1146 if (utf8_left == 0) {
1151 utf8_partial = (utf8_partial << 8) | c;
1152 if (utf8_left == 0) {
1158 b = (u >> 24) & 0xff;
1159 if (b != 0) { /* Four-byte sequence */
1161 b = (u >> 16) & 0xff;
1162 v = (v << 6) | (b & 0x3f);
1163 b = (u >> 8) & 0xff;
1164 v = (v << 6) | (b & 0x3f);
1166 v = (v << 6) | (b & 0x3f);
1167 } else if ((b = (u >> 16) & 0xff) != 0) {
1168 v = b & 0x0f; /* Three-byte sequence */
1169 b = (u >> 8) & 0xff;
1170 v = (v << 6) | (b & 0x3f);
1172 v = (v << 6) | (b & 0x3f);
1173 } else if ((b = (u >> 8) & 0xff) != 0) {
1174 v = b & 0x1f; /* Two-byte sequence */
1176 v = (v << 6) | (b & 0x3f);
1178 /* Send unicode char directly to console. */
1179 efi_cons_efiputchar(v);
1184 /* Anything left is illegal in UTF-8 sequence. */
1190 efi_cons_putchar(int c)
1192 unsigned char ch = c;
1195 * Don't use Teken when we're doing pure serial, or a multiple console
1196 * with video "primary" because that's also serial.
1198 if ((mode & (RB_SERIAL | RB_MULTIPLE)) != 0 || screen_buffer == NULL) {
1203 teken_input(&gfx_state.tg_teken, &ch, sizeof (ch));
1207 keybuf_getchar(void)
1211 for (i = 0; i < KEYBUFSZ; i++) {
1212 if (keybuf[i] != 0) {
1227 for (i = 0; i < KEYBUFSZ; i++) {
1235 * We are not reading input before keybuf is empty, so we are safe
1236 * just to fill keybuf from the beginning.
1239 keybuf_inschar(EFI_INPUT_KEY *key)
1242 switch (key->ScanCode) {
1243 case SCAN_UP: /* UP */
1244 keybuf[0] = 0x1b; /* esc */
1248 case SCAN_DOWN: /* DOWN */
1249 keybuf[0] = 0x1b; /* esc */
1253 case SCAN_RIGHT: /* RIGHT */
1254 keybuf[0] = 0x1b; /* esc */
1258 case SCAN_LEFT: /* LEFT */
1259 keybuf[0] = 0x1b; /* esc */
1264 keybuf[0] = CHAR_BACKSPACE;
1267 keybuf[0] = 0x1b; /* esc */
1270 keybuf[0] = key->UnicodeChar;
1281 status = conin->ReadKeyStroke(conin, &key);
1282 if (status == EFI_SUCCESS) {
1283 keybuf_inschar(&key);
1290 efi_readkey_ex(void)
1294 EFI_KEY_DATA key_data;
1297 status = coninex->ReadKeyStrokeEx(coninex, &key_data);
1298 if (status == EFI_SUCCESS) {
1299 kss = key_data.KeyState.KeyShiftState;
1301 if (kss & EFI_SHIFT_STATE_VALID) {
1304 * quick mapping to control chars, replace with
1307 if (kss & EFI_RIGHT_CONTROL_PRESSED ||
1308 kss & EFI_LEFT_CONTROL_PRESSED) {
1309 if (kp->UnicodeChar >= 'a' &&
1310 kp->UnicodeChar <= 'z') {
1311 kp->UnicodeChar -= 'a';
1317 * The shift state and/or toggle state may not be valid,
1318 * but we still can have ScanCode or UnicodeChar.
1320 if (kp->ScanCode == 0 && kp->UnicodeChar == 0)
1329 efi_cons_getchar(void)
1333 if ((c = keybuf_getchar()) != 0)
1338 if (coninex == NULL) {
1340 return (keybuf_getchar());
1342 if (efi_readkey_ex())
1343 return (keybuf_getchar());
1354 if (keybuf_ischar() || key_pending)
1358 * Some EFI implementation (u-boot for example) do not support
1360 * CheckEvent() can clear the signaled state.
1362 if (coninex != NULL) {
1363 if (coninex->WaitForKeyEx == NULL) {
1364 key_pending = efi_readkey_ex();
1366 status = BS->CheckEvent(coninex->WaitForKeyEx);
1367 key_pending = status == EFI_SUCCESS;
1370 if (conin->WaitForKey == NULL) {
1371 key_pending = efi_readkey();
1373 status = BS->CheckEvent(conin->WaitForKey);
1374 key_pending = status == EFI_SUCCESS;
1378 return (key_pending);
1381 /* Plain direct access to EFI OutputString(). */
1383 efi_cons_efiputchar(int c)
1389 buf[1] = 0; /* terminate string */
1391 status = conout->TestString(conout, buf);
1392 if (EFI_ERROR(status))
1394 conout->OutputString(conout, buf);