diff --git a/stand/efi/libefi/efi_console.c b/stand/efi/libefi/efi_console.c
index 1ed2be15d3d6..4c04461a5f92 100644
--- a/stand/efi/libefi/efi_console.c
+++ b/stand/efi/libefi/efi_console.c
@@ -1,1385 +1,1385 @@
 /*-
  * Copyright (c) 2000 Doug Rabson
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <efi.h>
 #include <efilib.h>
 #include <teken.h>
 #include <sys/reboot.h>
 #include <machine/metadata.h>
 #include <gfx_fb.h>
 #include <framebuffer.h>
 #include "bootstrap.h"
 
 extern EFI_GUID gop_guid;
 static EFI_GUID simple_input_ex_guid = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
 static SIMPLE_TEXT_OUTPUT_INTERFACE	*conout;
 static SIMPLE_INPUT_INTERFACE		*conin;
 static EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *coninex;
 static bool efi_started;
 
 static int mode;		/* Does ConOut have serial console? */
 
 static uint32_t utf8_left;
 static uint32_t utf8_partial;
 #ifdef TERM_EMU
 #define	DEFAULT_FGCOLOR EFI_LIGHTGRAY
 #define	DEFAULT_BGCOLOR EFI_BLACK
 
 #define	MAXARGS 8
 static int args[MAXARGS], argc;
 static int fg_c, bg_c, curx, cury;
 static int esc;
 
 void get_pos(int *x, int *y);
 void curs_move(int *_x, int *_y, int x, int y);
 static void CL(int);
 void HO(void);
 void end_term(void);
 #endif
 
 #define	TEXT_ROWS	24
 #define	TEXT_COLS	80
 
 static tf_bell_t	efi_cons_bell;
 static tf_cursor_t	efi_text_cursor;
 static tf_putchar_t	efi_text_putchar;
 static tf_fill_t	efi_text_fill;
 static tf_copy_t	efi_text_copy;
 static tf_param_t	efi_text_param;
 static tf_respond_t	efi_cons_respond;
 
 static teken_funcs_t tf = {
 	.tf_bell	= efi_cons_bell,
 	.tf_cursor	= efi_text_cursor,
 	.tf_putchar	= efi_text_putchar,
 	.tf_fill	= efi_text_fill,
 	.tf_copy	= efi_text_copy,
 	.tf_param	= efi_text_param,
 	.tf_respond	= efi_cons_respond,
 };
 
 static teken_funcs_t tfx = {
 	.tf_bell	= efi_cons_bell,
 	.tf_cursor	= gfx_fb_cursor,
 	.tf_putchar	= gfx_fb_putchar,
 	.tf_fill	= gfx_fb_fill,
 	.tf_copy	= gfx_fb_copy,
 	.tf_param	= gfx_fb_param,
 	.tf_respond	= efi_cons_respond,
 };
 
 #define	KEYBUFSZ 10
 static unsigned keybuf[KEYBUFSZ];	/* keybuf for extended codes */
 static int key_pending;
 
 static const unsigned char teken_color_to_efi_color[16] = {
 	EFI_BLACK,
 	EFI_RED,
 	EFI_GREEN,
 	EFI_BROWN,
 	EFI_BLUE,
 	EFI_MAGENTA,
 	EFI_CYAN,
 	EFI_LIGHTGRAY,
 	EFI_DARKGRAY,
 	EFI_LIGHTRED,
 	EFI_LIGHTGREEN,
 	EFI_YELLOW,
 	EFI_LIGHTBLUE,
 	EFI_LIGHTMAGENTA,
 	EFI_LIGHTCYAN,
 	EFI_WHITE
 };
 
 static void efi_cons_probe(struct console *);
 static int efi_cons_init(int);
 void efi_cons_putchar(int);
 int efi_cons_getchar(void);
 void efi_cons_efiputchar(int);
 int efi_cons_poll(void);
 static void cons_draw_frame(teken_attr_t *);
 
 struct console efi_console = {
 	"efi",
 	"EFI console",
 	C_WIDEOUT,
 	efi_cons_probe,
 	efi_cons_init,
 	efi_cons_putchar,
 	efi_cons_getchar,
 	efi_cons_poll
 };
 
 /*
  * This function is used to mark a rectangular image area so the scrolling
  * will know we need to copy the data from there.
  */
 void
 term_image_display(teken_gfx_t *state, const teken_rect_t *r)
 {
 	teken_pos_t p;
 	int idx;
 
 	if (screen_buffer == NULL)
 		return;
 
 	for (p.tp_row = r->tr_begin.tp_row;
 	    p.tp_row < r->tr_end.tp_row; p.tp_row++) {
 		for (p.tp_col = r->tr_begin.tp_col;
 		    p.tp_col < r->tr_end.tp_col; p.tp_col++) {
 			idx = p.tp_col + p.tp_row * state->tg_tp.tp_col;
 			if (idx >= state->tg_tp.tp_col * state->tg_tp.tp_row)
 				return;
 			screen_buffer[idx].a.ta_format |= TF_IMAGE;
 		}
 	}
 }
 
 /*
  * Not implemented.
  */
 static void
 efi_cons_bell(void *s __unused)
 {
 }
 
 static void
 efi_text_cursor(void *arg, const teken_pos_t *p)
 {
 	teken_gfx_t *state = arg;
 	UINTN col, row;
 
 	row = p->tp_row;
 	if (p->tp_row >= state->tg_tp.tp_row)
 		row = state->tg_tp.tp_row - 1;
 
 	col = p->tp_col;
 	if (p->tp_col >= state->tg_tp.tp_col)
 		col = state->tg_tp.tp_col - 1;
 
 	conout->SetCursorPosition(conout, col, row);
 }
 
 static void
 efi_text_printchar(teken_gfx_t *state, const teken_pos_t *p, bool autoscroll)
 {
 	UINTN a, attr;
 	struct text_pixel *px;
 	teken_color_t fg, bg, tmp;
 
 	px = screen_buffer + p->tp_col + p->tp_row * state->tg_tp.tp_col;
 	a = conout->Mode->Attribute;
 
 	fg = teken_256to16(px->a.ta_fgcolor);
 	bg = teken_256to16(px->a.ta_bgcolor);
 	if (px->a.ta_format & TF_BOLD)
 		fg |= TC_LIGHT;
 	if (px->a.ta_format & TF_BLINK)
 		bg |= TC_LIGHT;
 
 	if (px->a.ta_format & TF_REVERSE) {
 		tmp = fg;
 		fg = bg;
 		bg = tmp;
 	}
 
 	attr = EFI_TEXT_ATTR(teken_color_to_efi_color[fg],
 	    teken_color_to_efi_color[bg] & 0x7);
 
 	conout->SetCursorPosition(conout, p->tp_col, p->tp_row);
 
 	/* to prevent autoscroll, skip print of lower right char */
 	if (!autoscroll &&
 	    p->tp_row == state->tg_tp.tp_row - 1 &&
 	    p->tp_col == state->tg_tp.tp_col - 1)
 		return;
 
 	(void) conout->SetAttribute(conout, attr);
 	efi_cons_efiputchar(px->c);
 	(void) conout->SetAttribute(conout, a);
 }
 
 static void
 efi_text_putchar(void *s, const teken_pos_t *p, teken_char_t c,
     const teken_attr_t *a)
 {
 	teken_gfx_t *state = s;
 	EFI_STATUS status;
 	int idx;
 
 	idx = p->tp_col + p->tp_row * state->tg_tp.tp_col;
 	if (idx >= state->tg_tp.tp_col * state->tg_tp.tp_row)
 		return;
 
 	screen_buffer[idx].c = c;
 	screen_buffer[idx].a = *a;
 
 	efi_text_printchar(s, p, false);
 }
 
 static void
 efi_text_fill(void *arg, const teken_rect_t *r, teken_char_t c,
     const teken_attr_t *a)
 {
 	teken_gfx_t *state = arg;
 	teken_pos_t p;
 
 	if (state->tg_cursor_visible)
 		conout->EnableCursor(conout, FALSE);
 	for (p.tp_row = r->tr_begin.tp_row; p.tp_row < r->tr_end.tp_row;
 	    p.tp_row++)
 		for (p.tp_col = r->tr_begin.tp_col;
 		    p.tp_col < r->tr_end.tp_col; p.tp_col++)
 			efi_text_putchar(state, &p, c, a);
 	if (state->tg_cursor_visible)
 		conout->EnableCursor(conout, TRUE);
 }
 
 static void
 efi_text_copy_line(teken_gfx_t *state, int ncol, teken_pos_t *s,
     teken_pos_t *d, bool scroll)
 {
 	unsigned soffset, doffset;
 	teken_pos_t sp, dp;
 	int x;
 
 	soffset = s->tp_col + s->tp_row * state->tg_tp.tp_col;
 	doffset = d->tp_col + d->tp_row * state->tg_tp.tp_col;
 
 	sp = *s;
 	dp = *d;
 	for (x = 0; x < ncol; x++) {
 		sp.tp_col = s->tp_col + x;
 		dp.tp_col = d->tp_col + x;
 		if (!is_same_pixel(&screen_buffer[soffset + x],
 		    &screen_buffer[doffset + x])) {
 			screen_buffer[doffset + x] =
 			    screen_buffer[soffset + x];
 			if (!scroll)
 				efi_text_printchar(state, &dp, false);
 		} else if (scroll) {
 			/* Draw last char and trigger scroll. */
 			if (dp.tp_col + 1 == state->tg_tp.tp_col &&
 			    dp.tp_row + 1 == state->tg_tp.tp_row) {
 				efi_text_printchar(state, &dp, true);
 			}
 		}
 	}
 }
 
 static void
 efi_text_copy(void *arg, const teken_rect_t *r, const teken_pos_t *p)
 {
 	teken_gfx_t *state = arg;
 	unsigned doffset, soffset;
 	teken_pos_t d, s;
 	int nrow, ncol, x, y; /* Has to be signed - >= 0 comparison */
 	bool scroll = false;
 
 	/*
 	 * Copying is a little tricky. We must make sure we do it in
 	 * correct order, to make sure we don't overwrite our own data.
 	 */
 
 	nrow = r->tr_end.tp_row - r->tr_begin.tp_row;
 	ncol = r->tr_end.tp_col - r->tr_begin.tp_col;
 
 	/*
 	 * Check if we do copy whole screen.
 	 */
 	if (p->tp_row == 0 && p->tp_col == 0 &&
 	    nrow == state->tg_tp.tp_row - 2 && ncol == state->tg_tp.tp_col - 2)
 		scroll = true;
 
 	soffset = r->tr_begin.tp_col + r->tr_begin.tp_row * state->tg_tp.tp_col;
 	doffset = p->tp_col + p->tp_row * state->tg_tp.tp_col;
 
 	/* remove the cursor */
 	if (state->tg_cursor_visible)
 		conout->EnableCursor(conout, FALSE);
 
 	/*
 	 * Copy line by line.
 	 */
 	if (doffset <= soffset) {
 		s = r->tr_begin;
 		d = *p;
 		for (y = 0; y < nrow; y++) {
 			s.tp_row = r->tr_begin.tp_row + y;
 			d.tp_row = p->tp_row + y;
 
 			efi_text_copy_line(state, ncol, &s, &d, scroll);
 		}
 	} else {
 		for (y = nrow - 1; y >= 0; y--) {
 			s.tp_row = r->tr_begin.tp_row + y;
 			d.tp_row = p->tp_row + y;
 
 			efi_text_copy_line(state, ncol, &s, &d, false);
 		}
 	}
 
 	/* display the cursor */
 	if (state->tg_cursor_visible)
 		conout->EnableCursor(conout, TRUE);
 }
 
 static void
 efi_text_param(void *arg, int cmd, unsigned int value)
 {
 	teken_gfx_t *state = arg;
 
 	switch (cmd) {
 	case TP_SETLOCALCURSOR:
 		/*
 		 * 0 means normal (usually block), 1 means hidden, and
 		 * 2 means blinking (always block) for compatibility with
 		 * syscons.  We don't support any changes except hiding,
 		 * so must map 2 to 0.
 		 */
 		value = (value == 1) ? 0 : 1;
 		/* FALLTHROUGH */
 	case TP_SHOWCURSOR:
 		if (value != 0) {
 			conout->EnableCursor(conout, TRUE);
 			state->tg_cursor_visible = true;
 		} else {
 			conout->EnableCursor(conout, FALSE);
 			state->tg_cursor_visible = false;
 		}
 		break;
 	default:
 		/* Not yet implemented */
 		break;
 	}
 }
 
 /*
  * Not implemented.
  */
 static void
 efi_cons_respond(void *s __unused, const void *buf __unused,
     size_t len __unused)
 {
 }
 
 /*
  * Set up conin/conout/coninex to make sure we have input ready.
  */
 static void
 efi_cons_probe(struct console *cp)
 {
 	EFI_STATUS status;
 
 	conout = ST->ConOut;
 	conin = ST->ConIn;
 
 	/*
 	 * Call SetMode to work around buggy firmware.
 	 */
 	status = conout->SetMode(conout, conout->Mode->Mode);
 
 	if (coninex == NULL) {
 		status = BS->OpenProtocol(ST->ConsoleInHandle,
 		    &simple_input_ex_guid, (void **)&coninex,
 		    IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
 		if (status != EFI_SUCCESS)
 			coninex = NULL;
 	}
 
 	cp->c_flags |= C_PRESENTIN | C_PRESENTOUT;
 }
 
 static bool
 color_name_to_teken(const char *name, int *val)
 {
 	if (strcasecmp(name, "black") == 0) {
 		*val = TC_BLACK;
 		return (true);
 	}
 	if (strcasecmp(name, "red") == 0) {
 		*val = TC_RED;
 		return (true);
 	}
 	if (strcasecmp(name, "green") == 0) {
 		*val = TC_GREEN;
 		return (true);
 	}
 	if (strcasecmp(name, "brown") == 0) {
 		*val = TC_BROWN;
 		return (true);
 	}
 	if (strcasecmp(name, "blue") == 0) {
 		*val = TC_BLUE;
 		return (true);
 	}
 	if (strcasecmp(name, "magenta") == 0) {
 		*val = TC_MAGENTA;
 		return (true);
 	}
 	if (strcasecmp(name, "cyan") == 0) {
 		*val = TC_CYAN;
 		return (true);
 	}
 	if (strcasecmp(name, "white") == 0) {
 		*val = TC_WHITE;
 		return (true);
 	}
 	return (false);
 }
 
 static int
 efi_set_colors(struct env_var *ev, int flags, const void *value)
 {
 	int val = 0;
 	char buf[2];
 	const void *evalue;
 	const teken_attr_t *ap;
 	teken_attr_t a;
 
 	if (value == NULL)
 		return (CMD_OK);
 
 	if (color_name_to_teken(value, &val)) {
 		snprintf(buf, sizeof (buf), "%d", val);
 		evalue = buf;
 	} else {
 		char *end;
 
 		errno = 0;
 		val = (int)strtol(value, &end, 0);
 		if (errno != 0 || *end != '\0') {
 			printf("Allowed values are either ansi color name or "
 			    "number from range [0-7].\n");
 			return (CMD_OK);
 		}
 		evalue = value;
 	}
 
 	ap = teken_get_defattr(&gfx_state.tg_teken);
 	a = *ap;
 	if (strcmp(ev->ev_name, "teken.fg_color") == 0) {
 		/* is it already set? */
 		if (ap->ta_fgcolor == val)
 			return (CMD_OK);
 		a.ta_fgcolor = val;
 	}
 	if (strcmp(ev->ev_name, "teken.bg_color") == 0) {
 		/* is it already set? */
 		if (ap->ta_bgcolor == val)
 			return (CMD_OK);
 		a.ta_bgcolor = val;
 	}
 
 	/* Improve visibility */
 	if (a.ta_bgcolor == TC_WHITE)
 		a.ta_bgcolor |= TC_LIGHT;
 
 	teken_set_defattr(&gfx_state.tg_teken, &a);
 	cons_draw_frame(&a);
 	env_setenv(ev->ev_name, flags | EV_NOHOOK, evalue, NULL, NULL);
 	teken_input(&gfx_state.tg_teken, "\e[2J", 4);
 	return (CMD_OK);
 }
 
 #ifdef TERM_EMU
 /* Get cursor position. */
 void
 get_pos(int *x, int *y)
 {
 	*x = conout->Mode->CursorColumn;
 	*y = conout->Mode->CursorRow;
 }
 
 /* Move cursor to x rows and y cols (0-based). */
 void
 curs_move(int *_x, int *_y, int x, int y)
 {
 	conout->SetCursorPosition(conout, x, y);
 	if (_x != NULL)
 		*_x = conout->Mode->CursorColumn;
 	if (_y != NULL)
 		*_y = conout->Mode->CursorRow;
 }
  
 /* Clear internal state of the terminal emulation code. */
 void
 end_term(void)
 {
 	esc = 0;
 	argc = -1;
 }
 #endif
 
 static void
 efi_cons_rawputchar(int c)
 {
 	int i;
 	UINTN x, y;
 	conout->QueryMode(conout, conout->Mode->Mode, &x, &y);
 
 	if (c == '\t') {
 		int n;
 
 		n = 8 - ((conout->Mode->CursorColumn + 8) % 8);
 		for (i = 0; i < n; i++)
 			efi_cons_rawputchar(' ');
 	} else {
 #ifndef TERM_EMU
 		if (c == '\n')
 			efi_cons_efiputchar('\r');
 		efi_cons_efiputchar(c);
 #else
 		switch (c) {
 		case '\r':
 			curx = 0;
 			efi_cons_efiputchar('\r');
 			return;
 		case '\n':
 			efi_cons_efiputchar('\n');
 			efi_cons_efiputchar('\r');
 			cury++;
 			if (cury >= y)
 				cury--;
 			curx = 0;
 			return;
 		case '\b':
 			if (curx > 0) {
 				efi_cons_efiputchar('\b');
 				curx--;
 			}
 			return;
 		default:
 			efi_cons_efiputchar(c);
 			curx++;
 			if (curx > x-1) {
 				curx = 0;
 				cury++;
 			}
 			if (cury > y-1) {
 				curx = 0;
 				cury--;
 			}
 		}
 #endif
 	}
 	conout->EnableCursor(conout, TRUE);
 }
 
 #ifdef TERM_EMU
 /* Gracefully exit ESC-sequence processing in case of misunderstanding. */
 static void
 bail_out(int c)
 {
 	char buf[16], *ch;
 	int i;
 
 	if (esc) {
 		efi_cons_rawputchar('\033');
 		if (esc != '\033')
 			efi_cons_rawputchar(esc);
 		for (i = 0; i <= argc; ++i) {
 			sprintf(buf, "%d", args[i]);
 			ch = buf;
 			while (*ch)
 				efi_cons_rawputchar(*ch++);
 		}
 	}
 	efi_cons_rawputchar(c);
 	end_term();
 }
 
 /* Clear display from current position to end of screen. */
 static void
 CD(void)
 {
 	int i;
 	UINTN x, y;
 
 	get_pos(&curx, &cury);
 	if (curx == 0 && cury == 0) {
 		conout->ClearScreen(conout);
 		end_term();
 		return;
 	}
 
 	conout->QueryMode(conout, conout->Mode->Mode, &x, &y);
 	CL(0);  /* clear current line from cursor to end */
 	for (i = cury + 1; i < y-1; i++) {
 		curs_move(NULL, NULL, 0, i);
 		CL(0);
 	}
 	curs_move(NULL, NULL, curx, cury);
 	end_term();
 }
 
 /*
  * Absolute cursor move to args[0] rows and args[1] columns
  * (the coordinates are 1-based).
  */
 static void
 CM(void)
 {
 	if (args[0] > 0)
 		args[0]--;
 	if (args[1] > 0)
 		args[1]--;
 	curs_move(&curx, &cury, args[1], args[0]);
 	end_term();
 }
 
 /* Home cursor (left top corner), also called from mode command. */
 void
 HO(void)
 {
 	argc = 1;
 	args[0] = args[1] = 1;
 	CM();
 }
  
 /* Clear line from current position to end of line */
 static void
 CL(int direction)
 {
 	int i, len;
 	UINTN x, y;
 	CHAR16 *line;
 
 	conout->QueryMode(conout, conout->Mode->Mode, &x, &y);
 	switch (direction) {
 	case 0:	/* from cursor to end */
 		len = x - curx + 1;
 		break;
 	case 1:	/* from beginning to cursor */
 		len = curx;
 		break;
 	case 2:	/* entire line */
 		len = x;
 		break;
 	default:	/* NOTREACHED */
 		__unreachable();
 	}
  
 	if (cury == y - 1)
 		len--;
 
 	line = malloc(len * sizeof (CHAR16));
 	if (line == NULL) {
 		printf("out of memory\n");
 		return;
 	}
 	for (i = 0; i < len; i++)
 		line[i] = ' ';
 	line[len-1] = 0;
 
 	if (direction != 0)
 		curs_move(NULL, NULL, 0, cury);
  
 	conout->OutputString(conout, line);
 	/* restore cursor position */
 	curs_move(NULL, NULL, curx, cury);
 	free(line);
 	end_term();
 }
 
 static void
 get_arg(int c)
 {
 	if (argc < 0)
 		argc = 0;
 	args[argc] *= 10;
 	args[argc] += c - '0';
 }
 #endif
  
 /* Emulate basic capabilities of cons25 terminal */
 static void
 efi_term_emu(int c)
 {
 #ifdef TERM_EMU
 	static int ansi_col[] = {
 		0, 4, 2, 6, 1, 5, 3, 7
 	};
 	int t, i;
 	EFI_STATUS status;
  
 	switch (esc) {
 	case 0:
 		switch (c) {
 		case '\033':
 			esc = c;
 			break;
 		default:
 			efi_cons_rawputchar(c);
 			break;
 		}
 		break;
 	case '\033':
 		switch (c) {
 		case '[':
 			esc = c;
 			args[0] = 0;
 			argc = -1;
 			break;
 		default:
 			bail_out(c);
 			break;
 		}
 		break;
 	case '[':
 		switch (c) {
 		case ';':
 			if (argc < 0)
 				argc = 0;
 			else if (argc + 1 >= MAXARGS)
 				bail_out(c);
 			else
 				args[++argc] = 0;
 			break;
 		case 'H':		/* ho = \E[H */
 			if (argc < 0)
 				HO();
 			else if (argc == 1)
 				CM();
 			else
 				bail_out(c);
 			break;
 		case 'J':		/* cd = \E[J */
 			if (argc < 0)
 				CD();
 			else
 				bail_out(c);
 			break;
 		case 'm':
 			if (argc < 0) {
 				fg_c = DEFAULT_FGCOLOR;
 				bg_c = DEFAULT_BGCOLOR;
 			}
 			for (i = 0; i <= argc; ++i) {
 				switch (args[i]) {
 				case 0:		/* back to normal */
 					fg_c = DEFAULT_FGCOLOR;
 					bg_c = DEFAULT_BGCOLOR;
 					break;
 				case 1:		/* bold */
 					fg_c |= 0x8;
 					break;
 				case 4:		/* underline */
 				case 5:		/* blink */
 					bg_c |= 0x8;
 					break;
 				case 7:		/* reverse */
 					t = fg_c;
 					fg_c = bg_c;
 					bg_c = t;
 					break;
 				case 22:	/* normal intensity */
 					fg_c &= ~0x8;
 					break;
 				case 24:	/* not underline */
 				case 25:	/* not blinking */
 					bg_c &= ~0x8;
 					break;
 				case 30: case 31: case 32: case 33:
 				case 34: case 35: case 36: case 37:
 					fg_c = ansi_col[args[i] - 30];
 					break;
 				case 39:	/* normal */
 					fg_c = DEFAULT_FGCOLOR;
 					break;
 				case 40: case 41: case 42: case 43:
 				case 44: case 45: case 46: case 47:
 					bg_c = ansi_col[args[i] - 40];
 					break;
 				case 49:	/* normal */
 					bg_c = DEFAULT_BGCOLOR;
 					break;
 				}
 			}
 			conout->SetAttribute(conout, EFI_TEXT_ATTR(fg_c, bg_c));
 			end_term();
 			break;
 		default:
 			if (isdigit(c))
 				get_arg(c);
 			else
 				bail_out(c);
 			break;
 		}
 		break;
 	default:
 		bail_out(c);
 		break;
 	}
 #else
 	efi_cons_rawputchar(c);
 #endif
 }
 
 static int
 env_screen_nounset(struct env_var *ev __unused)
 {
 	if (gfx_state.tg_fb_type == FB_TEXT)
 		return (0);
 	return (EPERM);
 }
 
 static void
 cons_draw_frame(teken_attr_t *a)
 {
 	teken_attr_t attr = *a;
 	teken_color_t fg = a->ta_fgcolor;
 
 	attr.ta_fgcolor = attr.ta_bgcolor;
 	teken_set_defattr(&gfx_state.tg_teken, &attr);
 
 	gfx_fb_drawrect(0, 0, gfx_state.tg_fb.fb_width,
 	    gfx_state.tg_origin.tp_row, 1);
 	gfx_fb_drawrect(0,
 	    gfx_state.tg_fb.fb_height - gfx_state.tg_origin.tp_row - 1,
 	    gfx_state.tg_fb.fb_width, gfx_state.tg_fb.fb_height, 1);
 	gfx_fb_drawrect(0, gfx_state.tg_origin.tp_row,
 	    gfx_state.tg_origin.tp_col,
 	    gfx_state.tg_fb.fb_height - gfx_state.tg_origin.tp_row - 1, 1);
 	gfx_fb_drawrect(
 	    gfx_state.tg_fb.fb_width - gfx_state.tg_origin.tp_col - 1,
 	    gfx_state.tg_origin.tp_row, gfx_state.tg_fb.fb_width,
 	    gfx_state.tg_fb.fb_height, 1);
 
 	attr.ta_fgcolor = fg;
 	teken_set_defattr(&gfx_state.tg_teken, &attr);
 }
 
 bool
 cons_update_mode(bool use_gfx_mode)
 {
 	UINTN cols, rows;
 	const teken_attr_t *a;
 	teken_attr_t attr;
 	EFI_STATUS status;
 	char env[10], *ptr;
 
 	/*
 	 * Despite the use_gfx_mode, we want to make sure we call
 	 * efi_find_framebuffer(). This will populate the fb data,
 	 * which will be passed to kernel.
 	 */
 	if (efi_find_framebuffer(&gfx_state) == 0 && use_gfx_mode) {
 		int roff, goff, boff;
 
 		roff = ffs(gfx_state.tg_fb.fb_mask_red) - 1;
 		goff = ffs(gfx_state.tg_fb.fb_mask_green) - 1;
 		boff = ffs(gfx_state.tg_fb.fb_mask_blue) - 1;
 
 		(void) generate_cons_palette(cmap, COLOR_FORMAT_RGB,
 		    gfx_state.tg_fb.fb_mask_red >> roff, roff,
 		    gfx_state.tg_fb.fb_mask_green >> goff, goff,
 		    gfx_state.tg_fb.fb_mask_blue >> boff, boff);
 	} else {
 		/*
 		 * Either text mode was asked by user or we failed to
 		 * find frame buffer.
 		 */
 		gfx_state.tg_fb_type = FB_TEXT;
 	}
 
 	status = conout->QueryMode(conout, conout->Mode->Mode, &cols, &rows);
 	if (EFI_ERROR(status) || cols * rows == 0) {
 		cols = TEXT_COLS;
 		rows = TEXT_ROWS;
 	}
 
 	/*
 	 * When we have serial port listed in ConOut, use pre-teken emulator,
 	 * if built with.
 	 * The problem is, we can not output text on efi and comconsole when
 	 * efi also has comconsole bound. But then again, we need to have
 	 * terminal emulator for efi text mode to support the menu.
 	 * While teken is too expensive to be used on serial console, the
 	 * pre-teken emulator is light enough to be used on serial console.
 	 *
 	 * When doing multiple consoles (both serial and video),
 	 * also just use the old emulator. RB_MULTIPLE also implies
 	 * we're using a serial console.
 	 */
 #if defined(__i386__) || defined(__amd64__)
 	mode = parse_uefi_con_out();
 #else
 	mode = 0;
 #endif
 	if ((mode & (RB_SERIAL | RB_MULTIPLE)) == 0) {
 		conout->EnableCursor(conout, FALSE);
 		gfx_state.tg_cursor_visible = false;
 
 		if (gfx_state.tg_fb_type == FB_TEXT) {
 
 			gfx_state.tg_functions = &tf;
 			/* ensure the following are not set for text mode */
 			unsetenv("screen.height");
 			unsetenv("screen.width");
 			unsetenv("screen.depth");
 		} else {
 			uint32_t fb_height, fb_width;
 
 			fb_height = gfx_state.tg_fb.fb_height;
 			fb_width = gfx_state.tg_fb.fb_width;
 
 			/*
 			 * setup_font() can adjust terminal size.
-			 * Note, we assume 80x24 terminal first, this is
-			 * because the font selection will attempt to achieve
-			 * at least this terminal dimension and we do not
-			 * end up with too small font.
+			 * Note, we do use UEFI terminal dimensions first,
+			 * this is because the font selection will attempt
+			 * to achieve at least this terminal dimension and
+			 * we do not end up with too small font.
 			 */
-			gfx_state.tg_tp.tp_row = TEXT_ROWS;
-			gfx_state.tg_tp.tp_col = TEXT_COLS;
+			gfx_state.tg_tp.tp_row = rows;
+			gfx_state.tg_tp.tp_col = cols;
 			setup_font(&gfx_state, fb_height, fb_width);
 			rows = gfx_state.tg_tp.tp_row;
 			cols = gfx_state.tg_tp.tp_col;
 			/* Point of origin in pixels. */
 			gfx_state.tg_origin.tp_row = (fb_height -
 			    (rows * gfx_state.tg_font.vf_height)) / 2;
 			gfx_state.tg_origin.tp_col = (fb_width -
 			    (cols * gfx_state.tg_font.vf_width)) / 2;
 
 			/* UEFI gop has depth 32. */
 			gfx_state.tg_glyph_size = gfx_state.tg_font.vf_height *
 			    gfx_state.tg_font.vf_width * 4;
 			free(gfx_state.tg_glyph);
 			gfx_state.tg_glyph = malloc(gfx_state.tg_glyph_size);
 			if (gfx_state.tg_glyph == NULL)
 				return (false);
 
 			gfx_state.tg_functions = &tfx;
 			snprintf(env, sizeof (env), "%d", fb_height);
 			env_setenv("screen.height", EV_VOLATILE | EV_NOHOOK,
 			    env, env_noset, env_screen_nounset);
 			snprintf(env, sizeof (env), "%d", fb_width);
 			env_setenv("screen.width", EV_VOLATILE | EV_NOHOOK,
 			    env, env_noset, env_screen_nounset);
 			snprintf(env, sizeof (env), "%d",
 			    gfx_state.tg_fb.fb_bpp);
 			env_setenv("screen.depth", EV_VOLATILE | EV_NOHOOK,
 			    env, env_noset, env_screen_nounset);
 		}
 
 		/* Record our terminal screen size. */
 		gfx_state.tg_tp.tp_row = rows;
 		gfx_state.tg_tp.tp_col = cols;
 
 		teken_init(&gfx_state.tg_teken, gfx_state.tg_functions,
 		    &gfx_state);
 
 		free(screen_buffer);
 		screen_buffer = malloc(rows * cols * sizeof(*screen_buffer));
 		if (screen_buffer != NULL) {
 			teken_set_winsize(&gfx_state.tg_teken,
 			    &gfx_state.tg_tp);
 			a = teken_get_defattr(&gfx_state.tg_teken);
 			attr = *a;
 
 			/*
 			 * On first run, we set up the efi_set_colors()
 			 * callback. If the env is already set, we
 			 * pick up fg and bg color values from the environment.
 			 */
 			ptr = getenv("teken.fg_color");
 			if (ptr != NULL) {
 				attr.ta_fgcolor = strtol(ptr, NULL, 10);
 				ptr = getenv("teken.bg_color");
 				attr.ta_bgcolor = strtol(ptr, NULL, 10);
 
 				teken_set_defattr(&gfx_state.tg_teken, &attr);
 			} else {
 				snprintf(env, sizeof(env), "%d",
 				    attr.ta_fgcolor);
 				env_setenv("teken.fg_color", EV_VOLATILE, env,
 				    efi_set_colors, env_nounset);
 				snprintf(env, sizeof(env), "%d",
 				    attr.ta_bgcolor);
 				env_setenv("teken.bg_color", EV_VOLATILE, env,
 				    efi_set_colors, env_nounset);
 			}
 		}
 	}
 
 	if (screen_buffer == NULL) {
 		conout->EnableCursor(conout, TRUE);
 #ifdef TERM_EMU
 		conout->SetAttribute(conout, EFI_TEXT_ATTR(DEFAULT_FGCOLOR,
 		    DEFAULT_BGCOLOR));
 		end_term();
 		get_pos(&curx, &cury);
 		curs_move(&curx, &cury, curx, cury);
 		fg_c = DEFAULT_FGCOLOR;
 		bg_c = DEFAULT_BGCOLOR;
 #endif
 	} else {
 		/* Improve visibility */
 		if (attr.ta_bgcolor == TC_WHITE)
 			attr.ta_bgcolor |= TC_LIGHT;
 		teken_set_defattr(&gfx_state.tg_teken, &attr);
 
 		/* Draw frame around terminal area. */
 		cons_draw_frame(&attr);
 		/*
 		 * Erase display, this will also fill our screen
 		 * buffer.
 		 */
 		teken_input(&gfx_state.tg_teken, "\e[2J", 4);
 		gfx_state.tg_functions->tf_param(&gfx_state,
 		    TP_SHOWCURSOR, 1);
 	}
 
 	snprintf(env, sizeof (env), "%u", (unsigned)rows);
 	setenv("LINES", env, 1);
 	snprintf(env, sizeof (env), "%u", (unsigned)cols);
 	setenv("COLUMNS", env, 1);
 
 	return (true);
 }
 
 static int
 efi_cons_init(int arg)
 {
 	EFI_STATUS status;
 
 	if (efi_started)
 		return (0);
 
 	efi_started = true;
 
 	gfx_framework_init();
 	if (cons_update_mode(gfx_state.tg_fb_type != FB_TEXT))
 		return (0);
 
 	return (1);
 }
 
 static void
 input_partial(void)
 {
 	unsigned i;
 	uint32_t c;
 
 	if (utf8_left == 0)
 		return;
 
 	for (i = 0; i < sizeof(utf8_partial); i++) {
 		c = (utf8_partial >> (24 - (i << 3))) & 0xff;
 		if (c != 0)
 			efi_term_emu(c);
 	}
 	utf8_left = 0;
 	utf8_partial = 0;
 }
 
 static void
 input_byte(uint8_t c)
 {
 	if ((c & 0x80) == 0x00) {
 		/* One-byte sequence. */
 		input_partial();
 		efi_term_emu(c);
 		return;
 	}
 	if ((c & 0xe0) == 0xc0) {
 		/* Two-byte sequence. */
 		input_partial();
 		utf8_left = 1;
 		utf8_partial = c;
 		return;
 	}
 	if ((c & 0xf0) == 0xe0) {
 		/* Three-byte sequence. */
 		input_partial();
 		utf8_left = 2;
 		utf8_partial = c;
 		return;
 	}
 	if ((c & 0xf8) == 0xf0) {
 		/* Four-byte sequence. */
 		input_partial();
 		utf8_left = 3;
 		utf8_partial = c;
 		return;
 	}
 	if ((c & 0xc0) == 0x80) {
 		/* Invalid state? */
 		if (utf8_left == 0) {
 			efi_term_emu(c);
 			return;
 		}
 		utf8_left--;
 		utf8_partial = (utf8_partial << 8) | c;
 		if (utf8_left == 0) {
 			uint32_t v, u;
 			uint8_t b;
 
 			v = 0;
 			u = utf8_partial;
 			b = (u >> 24) & 0xff;
 			if (b != 0) {		/* Four-byte sequence */
 				v = b & 0x07;
 				b = (u >> 16) & 0xff;
 				v = (v << 6) | (b & 0x3f);
 				b = (u >> 8) & 0xff;
 				v = (v << 6) | (b & 0x3f);
 				b = u & 0xff;
 				v = (v << 6) | (b & 0x3f);
 			} else if ((b = (u >> 16) & 0xff) != 0) {
 				v = b & 0x0f;	/* Three-byte sequence */
 				b = (u >> 8) & 0xff;
 				v = (v << 6) | (b & 0x3f);
 				b = u & 0xff;
 				v = (v << 6) | (b & 0x3f);
 			} else if ((b = (u >> 8) & 0xff) != 0) {
 				v = b & 0x1f;	/* Two-byte sequence */
 				b = u & 0xff;
 				v = (v << 6) | (b & 0x3f);
 			}
 			/* Send unicode char directly to console. */
 			efi_cons_efiputchar(v);
 			utf8_partial = 0;
 		}
 		return;
 	}
 	/* Anything left is illegal in UTF-8 sequence. */
 	input_partial();
 	efi_term_emu(c);
 }
 
 void
 efi_cons_putchar(int c)
 {
 	unsigned char ch = c;
 
 	/*
 	 * Don't use Teken when we're doing pure serial, or a multiple console
 	 * with video "primary" because that's also serial.
 	 */
 	if ((mode & (RB_SERIAL | RB_MULTIPLE)) != 0 || screen_buffer == NULL) {
 		input_byte(ch);
 		return;
 	}
 
 	teken_input(&gfx_state.tg_teken, &ch, sizeof (ch));
 }
 
 static int
 keybuf_getchar(void)
 {
 	int i, c = 0;
 
 	for (i = 0; i < KEYBUFSZ; i++) {
 		if (keybuf[i] != 0) {
 			c = keybuf[i];
 			keybuf[i] = 0;
 			break;
 		}
 	}
 
 	return (c);
 }
 
 static bool
 keybuf_ischar(void)
 {
 	int i;
 
 	for (i = 0; i < KEYBUFSZ; i++) {
 		if (keybuf[i] != 0)
 			return (true);
 	}
 	return (false);
 }
 
 /*
  * We are not reading input before keybuf is empty, so we are safe
  * just to fill keybuf from the beginning.
  */
 static void
 keybuf_inschar(EFI_INPUT_KEY *key)
 {
 
 	switch (key->ScanCode) {
 	case SCAN_UP: /* UP */
 		keybuf[0] = 0x1b;	/* esc */
 		keybuf[1] = '[';
 		keybuf[2] = 'A';
 		break;
 	case SCAN_DOWN: /* DOWN */
 		keybuf[0] = 0x1b;	/* esc */
 		keybuf[1] = '[';
 		keybuf[2] = 'B';
 		break;
 	case SCAN_RIGHT: /* RIGHT */
 		keybuf[0] = 0x1b;	/* esc */
 		keybuf[1] = '[';
 		keybuf[2] = 'C';
 		break;
 	case SCAN_LEFT: /* LEFT */
 		keybuf[0] = 0x1b;	/* esc */
 		keybuf[1] = '[';
 		keybuf[2] = 'D';
 		break;
 	case SCAN_DELETE:
 		keybuf[0] = CHAR_BACKSPACE;
 		break;
 	case SCAN_ESC:
 		keybuf[0] = 0x1b;	/* esc */
 		break;
 	default:
 		keybuf[0] = key->UnicodeChar;
 		break;
 	}
 }
 
 static bool
 efi_readkey(void)
 {
 	EFI_STATUS status;
 	EFI_INPUT_KEY key;
 
 	status = conin->ReadKeyStroke(conin, &key);
 	if (status == EFI_SUCCESS) {
 		keybuf_inschar(&key);
 		return (true);
 	}
 	return (false);
 }
 
 static bool
 efi_readkey_ex(void)
 {
 	EFI_STATUS status;
 	EFI_INPUT_KEY *kp;
 	EFI_KEY_DATA  key_data;
 	uint32_t kss;
 
 	status = coninex->ReadKeyStrokeEx(coninex, &key_data);
 	if (status == EFI_SUCCESS) {
 		kss = key_data.KeyState.KeyShiftState;
 		kp = &key_data.Key;
 		if (kss & EFI_SHIFT_STATE_VALID) {
 
 			/*
 			 * quick mapping to control chars, replace with
 			 * map lookup later.
 			 */
 			if (kss & EFI_RIGHT_CONTROL_PRESSED ||
 			    kss & EFI_LEFT_CONTROL_PRESSED) {
 				if (kp->UnicodeChar >= 'a' &&
 				    kp->UnicodeChar <= 'z') {
 					kp->UnicodeChar -= 'a';
 					kp->UnicodeChar++;
 				}
 			}
 		}
 		/*
 		 * The shift state and/or toggle state may not be valid,
 		 * but we still can have ScanCode or UnicodeChar.
 		 */
 		if (kp->ScanCode == 0 && kp->UnicodeChar == 0)
 			return (false);
 		keybuf_inschar(kp);
 		return (true);
 	}
 	return (false);
 }
 
 int
 efi_cons_getchar(void)
 {
 	int c;
 
 	if ((c = keybuf_getchar()) != 0)
 		return (c);
 
 	key_pending = 0;
 
 	if (coninex == NULL) {
 		if (efi_readkey())
 			return (keybuf_getchar());
 	} else {
 		if (efi_readkey_ex())
 			return (keybuf_getchar());
 	}
 
 	return (-1);
 }
 
 int
 efi_cons_poll(void)
 {
 	EFI_STATUS status;
 
 	if (keybuf_ischar() || key_pending)
 		return (1);
 
 	/*
 	 * Some EFI implementation (u-boot for example) do not support
 	 * WaitForKey().
 	 * CheckEvent() can clear the signaled state.
 	 */
 	if (coninex != NULL) {
 		if (coninex->WaitForKeyEx == NULL) {
 			key_pending = efi_readkey_ex();
 		} else {
 			status = BS->CheckEvent(coninex->WaitForKeyEx);
 			key_pending = status == EFI_SUCCESS;
 		}
 	} else {
 		if (conin->WaitForKey == NULL) {
 			key_pending = efi_readkey();
 		} else {
 			status = BS->CheckEvent(conin->WaitForKey);
 			key_pending = status == EFI_SUCCESS;
 		}
 	}
 
 	return (key_pending);
 }
 
 /* Plain direct access to EFI OutputString(). */
 void
 efi_cons_efiputchar(int c)
 {
 	CHAR16 buf[2];
 	EFI_STATUS status;
 
 	buf[0] = c;
         buf[1] = 0;     /* terminate string */
 
 	status = conout->TestString(conout, buf);
 	if (EFI_ERROR(status))
 		buf[0] = '?';
 	conout->OutputString(conout, buf);
 }