Print this page
NEX-16819 loader UEFI support
Includes work by Toomas Soome <tsoome@me.com>
Upstream commits:
loader: pxe receive cleanup
9475 libefi: Do not return only if ReceiveFilter
installboot: should support efi system partition
8931 boot1.efi: scan all display modes rather than
loader: spinconsole updates
loader: gfx experiment to try GOP Blt() function.
sha1 build test
loader: add sha1 hash calculation
common/sha1: update for loader build
loader: biosdisk rework
uts: 32-bit kernel FB needs mapping in low memory
uts: add diag-device
uts: boot console mirror with diag-device
uts: enable very early console on ttya
kmdb: add diag-device as input/output device
uts: test VGA memory exclusion from mapping
uts: clear boot mapping and protect boot pages test
uts: add dboot map debug printf
uts: need to release FB pages in release_bootstrap()
uts: add screenmap ioctl
uts: update sys/queue.h
loader: add illumos uts/common to include path
loader: tem/gfx font cleanup
loader: vbe checks
uts: gfx_private set KD_TEXT when KD_RESETTEXT is
uts: gfx 8-bit update
loader: gfx 8-bit fix
loader: always set media size from partition.
uts: MB2 support for 32-bit kernel
loader: x86 should have tem 80x25
uts: x86 should have tem 80x25
uts: font update
loader: font update
uts: tem attributes
loader: tem.c comment added
uts: use font module
loader: add font module
loader: build rules for new font setup
uts: gfx_private update for new font structure
uts: early boot update for new font structure
uts: font update
uts: font build rules update for new fonts
uts: tem update to new font structure
loader: module.c needs to include tem_impl.h
uts: gfx_private 8x16 font rework
uts: make font_lookup public
loader: font rework
uts: font rework
9259 libefi: efi_alloc_and_read should check for PMBR
uts: tem utf-8 support
loader: implement tem utf-8 support
loader: tem should be able to display UTF-8
7784 uts: console input should support utf-8
7796 uts: ldterm default to utf-8
uts: do not reset serial console
uts: set up colors even if tem is not console
uts: add type for early boot properties
uts: gfx_private experiment with drm and vga
uts: gfx_private should use setmode drm callback.
uts: identify FB types and set up gfx_private based
loader: replace gop and vesa with framebuffer
uts: boot needs simple tem to support mdb
uts: boot_keyboard should emit esc sequences for
uts: gfx_private FB showuld be written by line
kmdb: set terminal window size
uts: gfx_private needs to keep track of early boot FB
pnglite: move pnglite to usr/src/common
loader: gfx_fb
ficl-sys: add gfx primitives
loader: add illumos.png logo
ficl: add fb-putimage
loader: add png support
loader: add alpha blending for gfx_fb
loader: use term-drawrect for menu frame
ficl: add simple gfx words
uts: provide fb_info via fbgattr dev_specific array.
uts: gfx_private add alpha blending
uts: update sys/ascii.h
uts: tem OSC support (incomplete)
uts: implement env module support and use data from
uts: tem get colors from early boot data
loader: use crc32 from libstand (libz)
loader: optimize for size
loader: pass tem info to the environment
loader: import tem for loader console
loader: UEFI loader needs to set ISADIR based on
loader: need UEFI32 support
8918 loader.efi: add vesa edid support
uts: tem_safe_pix_clear_prom_output() should only
uts: tem_safe_pix_clear_entire_screen() should use
uts: tem_safe_check_first_time() should query cursor
uts: tem implement cls callback & visual_io v4
uts: gfx_vgatext use block cursor for vgatext
uts: gfx_private implement cls callback & visual_io
uts: gfx_private bitmap framebuffer implementation
uts: early start frame buffer console support
uts: font functions should check the input char
uts: font rendering should support 16/24/32bit depths
uts: use smallest font as fallback default.
uts: update terminal dimensions based on selected
7834 uts: vgatext should use gfx_private
uts: add spacing property to 8859-1.bdf
terminfo: add underline for sun-color
terminfo: sun-color has 16 colors
uts: add font load callback type
loader: do not repeat int13 calls with error 0x20 and
8905 loader: add skein/edonr support
8904 common/crypto: make skein and edonr loader
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Revert "NEX-16819 loader UEFI support"
This reverts commit ec06b9fc617b99234e538bf2e7e4d02a24993e0c.
Reverting due to failures in the zfs-tests and the sharefs-tests
NEX-16819 loader UEFI support
Includes work by Toomas Soome <tsoome@me.com>
Upstream commits:
loader: pxe receive cleanup
9475 libefi: Do not return only if ReceiveFilter
installboot: should support efi system partition
8931 boot1.efi: scan all display modes rather than
loader: spinconsole updates
loader: gfx experiment to try GOP Blt() function.
sha1 build test
loader: add sha1 hash calculation
common/sha1: update for loader build
loader: biosdisk rework
uts: 32-bit kernel FB needs mapping in low memory
uts: add diag-device
uts: boot console mirror with diag-device
uts: enable very early console on ttya
kmdb: add diag-device as input/output device
uts: test VGA memory exclusion from mapping
uts: clear boot mapping and protect boot pages test
uts: add dboot map debug printf
uts: need to release FB pages in release_bootstrap()
uts: add screenmap ioctl
uts: update sys/queue.h
loader: add illumos uts/common to include path
loader: tem/gfx font cleanup
loader: vbe checks
uts: gfx_private set KD_TEXT when KD_RESETTEXT is
uts: gfx 8-bit update
loader: gfx 8-bit fix
loader: always set media size from partition.
uts: MB2 support for 32-bit kernel
loader: x86 should have tem 80x25
uts: x86 should have tem 80x25
uts: font update
loader: font update
uts: tem attributes
loader: tem.c comment added
uts: use font module
loader: add font module
loader: build rules for new font setup
uts: gfx_private update for new font structure
uts: early boot update for new font structure
uts: font update
uts: font build rules update for new fonts
uts: tem update to new font structure
loader: module.c needs to include tem_impl.h
uts: gfx_private 8x16 font rework
uts: make font_lookup public
loader: font rework
uts: font rework
libefi: efi_alloc_and_read should check for PMBR
uts: tem utf-8 support
loader: implement tem utf-8 support
loader: tem should be able to display UTF-8
7784 uts: console input should support utf-8
7796 uts: ldterm default to utf-8
uts: do not reset serial console
uts: set up colors even if tem is not console
uts: add type for early boot properties
uts: gfx_private experiment with drm and vga
uts: gfx_private should use setmode drm callback.
uts: identify FB types and set up gfx_private based
loader: replace gop and vesa with framebuffer
uts: boot needs simple tem to support mdb
uts: boot_keyboard should emit esc sequences for
uts: gfx_private FB showuld be written by line
kmdb: set terminal window size
uts: gfx_private needs to keep track of early boot FB
pnglite: move pnglite to usr/src/common
loader: gfx_fb
ficl-sys: add gfx primitives
loader: add illumos.png logo
ficl: add fb-putimage
loader: add png support
loader: add alpha blending for gfx_fb
loader: use term-drawrect for menu frame
ficl: add simple gfx words
uts: provide fb_info via fbgattr dev_specific array.
uts: gfx_private add alpha blending
uts: update sys/ascii.h
uts: tem OSC support (incomplete)
uts: implement env module support and use data from
uts: tem get colors from early boot data
loader: use crc32 from libstand (libz)
loader: optimize for size
loader: pass tem info to the environment
loader: import tem for loader console
loader: UEFI loader needs to set ISADIR based on
loader: need UEFI32 support
8918 loader.efi: add vesa edid support
uts: tem_safe_pix_clear_prom_output() should only
uts: tem_safe_pix_clear_entire_screen() should use
uts: tem_safe_check_first_time() should query cursor
uts: tem implement cls callback & visual_io v4
uts: gfx_vgatext use block cursor for vgatext
uts: gfx_private implement cls callback & visual_io
uts: gfx_private bitmap framebuffer implementation
uts: early start frame buffer console support
uts: font functions should check the input char
uts: font rendering should support 16/24/32bit depths
uts: use smallest font as fallback default.
uts: update terminal dimensions based on selected
7834 uts: vgatext should use gfx_private
uts: add spacing property to 8859-1.bdf
terminfo: add underline for sun-color
terminfo: sun-color has 16 colors
uts: add font load callback type
loader: do not repeat int13 calls with error 0x20 and
8905 loader: add skein/edonr support
8904 common/crypto: make skein and edonr loader
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
@@ -23,481 +23,521 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
#include <efi.h>
#include <efilib.h>
+#include <sys/tem_impl.h>
+#include <sys/multiboot2.h>
+#include <machine/metadata.h>
+#include <gfx_fb.h>
#include "bootstrap.h"
+struct efi_fb efifb;
+EFI_GRAPHICS_OUTPUT *gop;
+EFI_UGA_DRAW_PROTOCOL *uga;
+
+static EFI_GUID ccontrol_protocol_guid = EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
+static EFI_CONSOLE_CONTROL_PROTOCOL *console_control;
+static EFI_GUID simple_input_ex_guid = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
+static EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *coninex;
static SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
static SIMPLE_INPUT_INTERFACE *conin;
+static EFI_CONSOLE_CONTROL_SCREEN_MODE console_mode;
-#ifdef TERM_EMU
-#define DEFAULT_FGCOLOR EFI_LIGHTGRAY
-#define DEFAULT_BGCOLOR EFI_BLACK
+/* mode change callback and argument from tem */
+static vis_modechg_cb_t modechg_cb;
+static struct vis_modechg_arg *modechg_arg;
+static tem_vt_state_t tem;
-#define MAXARGS 8
#define KEYBUFSZ 10
static unsigned keybuf[KEYBUFSZ]; /* keybuf for extended codes */
-static int args[MAXARGS], argc;
-static int fg_c, bg_c;
-static UINTN curx, cury;
-static int esc;
-void get_pos(UINTN *x, UINTN *y);
-void curs_move(UINTN *_x, UINTN *_y, UINTN x, UINTN y);
-static void CL(int);
-void HO(void);
-void end_term(void);
-#endif
+static const unsigned char solaris_color_to_efi_color[16] = {
+ EFI_WHITE,
+ EFI_BLACK,
+ EFI_BLUE,
+ EFI_GREEN,
+ EFI_CYAN,
+ EFI_RED,
+ EFI_MAGENTA,
+ EFI_BROWN,
+ EFI_LIGHTGRAY,
+ EFI_DARKGRAY,
+ EFI_LIGHTBLUE,
+ EFI_LIGHTGREEN,
+ EFI_LIGHTCYAN,
+ EFI_LIGHTRED,
+ EFI_LIGHTMAGENTA,
+ EFI_YELLOW
+};
+#define DEFAULT_FGCOLOR EFI_LIGHTGRAY
+#define DEFAULT_BGCOLOR EFI_BLACK
+
+extern int efi_find_framebuffer(struct efi_fb *efifb);
+
+static void efi_framebuffer_setup(void);
static void efi_cons_probe(struct console *);
static int efi_cons_init(struct console *, int);
-void efi_cons_putchar(struct console *, int);
-int efi_cons_getchar(struct console *);
-void efi_cons_efiputchar(int);
-int efi_cons_poll(struct console *);
+static void efi_cons_putchar(struct console *, int);
+static void efi_cons_efiputchar(int);
+static int efi_cons_getchar(struct console *);
+static int efi_cons_poll(struct console *);
+static int efi_cons_ioctl(struct console *cp, int cmd, void *data);
+static int efi_fb_devinit(struct vis_devinit *);
+static void efi_cons_cursor(struct vis_conscursor *);
+
+static int efi_text_devinit(struct vis_devinit *);
+static int efi_text_cons_clear(struct vis_consclear *);
+static void efi_text_cons_copy(struct vis_conscopy *);
+static void efi_text_cons_display(struct vis_consdisplay *);
+
struct console efi_console = {
- "text",
- "EFI console",
- C_WIDEOUT,
- efi_cons_probe,
- efi_cons_init,
- efi_cons_putchar,
- efi_cons_getchar,
- efi_cons_poll,
- 0
+ .c_name = "text",
+ .c_desc = "EFI console",
+ .c_flags = C_WIDEOUT,
+ .c_probe = efi_cons_probe,
+ .c_init = efi_cons_init,
+ .c_out = efi_cons_putchar,
+ .c_in = efi_cons_getchar,
+ .c_ready = efi_cons_poll,
+ .c_ioctl = efi_cons_ioctl,
+ .c_private = NULL
};
-#ifdef TERM_EMU
+static struct vis_identifier fb_ident = { "efi_fb" };
+static struct vis_identifier text_ident = { "efi_text" };
-/* Get cursor position. */
+struct visual_ops fb_ops = {
+ .ident = &fb_ident,
+ .kdsetmode = NULL,
+ .devinit = efi_fb_devinit,
+ .cons_copy = NULL,
+ .cons_display = NULL,
+ .cons_cursor = efi_cons_cursor,
+ .cons_clear = NULL,
+ .cons_put_cmap = NULL
+};
+
+struct visual_ops text_ops = {
+ .ident = &text_ident,
+ .kdsetmode = NULL,
+ .devinit = efi_text_devinit,
+ .cons_copy = efi_text_cons_copy,
+ .cons_display = efi_text_cons_display,
+ .cons_cursor = efi_cons_cursor,
+ .cons_clear = efi_text_cons_clear,
+ .cons_put_cmap = NULL
+};
+
+/*
+ * platform specific functions for tem
+ */
+int
+plat_stdout_is_framebuffer(void)
+{
+ return (console_mode == EfiConsoleControlScreenGraphics);
+}
+
void
-get_pos(UINTN *x, UINTN *y)
+plat_tem_hide_prom_cursor(void)
{
- *x = conout->Mode->CursorColumn;
- *y = conout->Mode->CursorRow;
+ conout->EnableCursor(conout, FALSE);
}
-/* Move cursor to x rows and y cols (0-based). */
void
-curs_move(UINTN *_x, UINTN *_y, UINTN x, UINTN y)
+plat_tem_get_prom_pos(uint32_t *row, uint32_t *col)
{
- conout->SetCursorPosition(conout, x, y);
- if (_x != NULL)
- *_x = conout->Mode->CursorColumn;
- if (_y != NULL)
- *_y = conout->Mode->CursorRow;
+ if (console_mode == EfiConsoleControlScreenText) {
+ *col = (uint32_t)conout->Mode->CursorColumn;
+ *row = (uint32_t)conout->Mode->CursorRow;
+ } else {
+ *col = 0;
+ *row = 0;
+ }
}
-/* Clear internal state of the terminal emulation code. */
+/*
+ * plat_tem_get_prom_size() is supposed to return screen size
+ * in chars. Return real data for text mode and TEM defaults for graphical
+ * mode, so the tem can compute values based on default and font.
+ */
void
-end_term(void)
+plat_tem_get_prom_size(size_t *height, size_t *width)
{
- esc = 0;
- argc = -1;
+ UINTN cols, rows;
+ if (console_mode == EfiConsoleControlScreenText) {
+ (void) conout->QueryMode(conout, conout->Mode->Mode,
+ &cols, &rows);
+ *height = (size_t)rows;
+ *width = (size_t)cols;
+ } else {
+ *height = TEM_DEFAULT_ROWS;
+ *width = TEM_DEFAULT_COLS;
+ }
}
-#endif
-
-static void
-efi_cons_probe(struct console *cp)
+/*
+ * Callback to notify about console mode change.
+ * mode is value from enum EFI_CONSOLE_CONTROL_SCREEN_MODE.
+ */
+void
+plat_cons_update_mode(int mode)
{
- conout = ST->ConOut;
- conin = ST->ConIn;
- cp->c_flags |= C_PRESENTIN | C_PRESENTOUT;
+ EFI_STATUS status;
+ UINTN cols, rows;
+ struct vis_devinit devinit;
+
+ /* Make sure we have usable console. */
+ if (efi_find_framebuffer(&efifb)) {
+ console_mode = EfiConsoleControlScreenText;
+ } else {
+ efi_framebuffer_setup();
+ if (mode != -1 && console_mode != mode)
+ console_mode = mode;
+ }
+
+ if (console_control != NULL)
+ (void)console_control->SetMode(console_control, console_mode);
+
+ /* some firmware enables the cursor when switching modes */
+ conout->EnableCursor(conout, FALSE);
+ if (console_mode == EfiConsoleControlScreenText) {
+ (void)conout->QueryMode(conout, conout->Mode->Mode,
+ &cols, &rows);
+ devinit.version = VIS_CONS_REV;
+ devinit.width = cols;
+ devinit.height = rows;
+ devinit.depth = 4;
+ devinit.linebytes = cols;
+ devinit.color_map = NULL;
+ devinit.mode = VIS_TEXT;
+ efi_console.c_private = &text_ops;
+ } else {
+ devinit.version = VIS_CONS_REV;
+ devinit.width = gfx_fb.framebuffer_common.framebuffer_width;
+ devinit.height = gfx_fb.framebuffer_common.framebuffer_height;
+ devinit.depth = gfx_fb.framebuffer_common.framebuffer_bpp;
+ devinit.linebytes = gfx_fb.framebuffer_common.framebuffer_pitch;
+ devinit.color_map = gfx_fb_color_map;
+ devinit.mode = VIS_PIXEL;
+ efi_console.c_private = &fb_ops;
+ }
+
+ modechg_cb(modechg_arg, &devinit);
}
static int
-efi_cons_init(struct console *cp __attribute((unused)),
- int arg __attribute((unused)))
+efi_fb_devinit(struct vis_devinit *data)
{
- conout->SetAttribute(conout, EFI_TEXT_ATTR(DEFAULT_FGCOLOR,
- DEFAULT_BGCOLOR));
-#ifdef TERM_EMU
- end_term();
- get_pos(&curx, &cury);
- curs_move(&curx, &cury, curx, cury);
- fg_c = DEFAULT_FGCOLOR;
- bg_c = DEFAULT_BGCOLOR;
- memset(keybuf, 0, KEYBUFSZ);
-#endif
- conout->EnableCursor(conout, TRUE);
- return 0;
+ if (console_mode != EfiConsoleControlScreenGraphics)
+ return (1);
+
+ data->version = VIS_CONS_REV;
+ data->width = gfx_fb.framebuffer_common.framebuffer_width;
+ data->height = gfx_fb.framebuffer_common.framebuffer_height;
+ data->depth = gfx_fb.framebuffer_common.framebuffer_bpp;
+ data->linebytes = gfx_fb.framebuffer_common.framebuffer_pitch;
+ data->color_map = gfx_fb_color_map;
+ data->mode = VIS_PIXEL;
+
+ modechg_cb = data->modechg_cb;
+ modechg_arg = data->modechg_arg;
+
+ return (0);
}
-static void
-efi_cons_rawputchar(int c)
+static int
+efi_text_devinit(struct vis_devinit *data)
{
- int i;
- UINTN x, y;
- conout->QueryMode(conout, conout->Mode->Mode, &x, &y);
- static int ignorenl = 0;
+ UINTN cols, rows;
- if (c == '\t')
- /* XXX lame tab expansion */
- for (i = 0; i < 8; i++)
- efi_cons_rawputchar(' ');
- else {
-#ifndef TERM_EMU
- if (c == '\n')
- efi_cons_efiputchar('\r');
- else
- efi_cons_efiputchar(c);
-#else
- switch (c) {
- case '\r':
- curx = 0;
- break;
- case '\n':
- if (ignorenl)
- ignorenl = 0;
- else
- cury++;
- if ((efi_console.c_flags & C_MODERAW) == 0)
- curx = 0;
- if (cury >= y) {
- efi_cons_efiputchar('\n');
- cury--;
- }
- break;
- case '\b':
- if (curx > 0)
- curx--;
- break;
- default:
- if (curx > x) {
- curx = 0;
- cury++;
- curs_move(&curx, &cury, curx, cury);
- }
- if ((efi_console.c_flags & C_MODERAW) == 0) {
- if (cury > y-1) {
- curx = 0;
- efi_cons_efiputchar('\n');
- cury--;
- curs_move(&curx, &cury, curx, cury);
- }
- }
- efi_cons_efiputchar(c);
- curx++;
- if ((efi_console.c_flags & C_MODERAW) == 0) {
- if (curx == x) {
- curx = 0;
- ignorenl = 1;
- }
- } else if (curx == x) {
- curx = 0;
- if (cury == y)
- efi_cons_efiputchar('\n');
- else
- cury++;
- }
- }
- curs_move(&curx, &cury, curx, cury);
-#endif
- }
+ if (console_mode != EfiConsoleControlScreenText)
+ return (1);
+
+ (void)conout->QueryMode(conout, conout->Mode->Mode, &cols, &rows);
+ data->version = VIS_CONS_REV;
+ data->width = cols;
+ data->height = rows;
+ data->depth = 4;
+ data->linebytes = cols;
+ data->color_map = NULL;
+ data->mode = VIS_TEXT;
+
+ modechg_cb = data->modechg_cb;
+ modechg_arg = data->modechg_arg;
+
+ return (0);
}
-/* Gracefully exit ESC-sequence processing in case of misunderstanding. */
-static void
-bail_out(int c)
+static int
+efi_text_cons_clear(struct vis_consclear *ca)
{
- char buf[16], *ch;
- int i;
+ EFI_STATUS st;
+ UINTN attr = conout->Mode->Attribute & 0x0F;
- 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();
+ attr = EFI_TEXT_ATTR(attr,
+ solaris_color_to_efi_color[ca->bg_color & 0xF]);
+ st = conout->SetAttribute(conout, attr);
+ if (EFI_ERROR(st))
+ return (1);
+ st = conout->ClearScreen(conout);
+ if (EFI_ERROR(st))
+ return (1);
+ return (0);
}
-/* Clear display from current position to end of screen. */
static void
-CD(void) {
- UINTN i, x, y;
+efi_text_cons_copy(struct vis_conscopy *ma)
+{
+ UINTN col, row;
- get_pos(&curx, &cury);
- if (curx == 0 && cury == 0) {
- conout->ClearScreen(conout);
- end_term();
- return;
- }
+ col = 0;
+ row = ma->e_row;
+ conout->SetCursorPosition(conout, col, row);
- 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();
+ efi_cons_efiputchar('\n');
}
-/*
- * Absolute cursor move to args[0] rows and args[1] columns
- * (the coordinates are 1-based).
- */
static void
-CM(void)
+efi_text_cons_display(struct vis_consdisplay *da)
{
- if (args[0] > 0)
- args[0]--;
- if (args[1] > 0)
- args[1]--;
- curs_move(&curx, &cury, args[1], args[0]);
- end_term();
+ EFI_STATUS st;
+ UINTN attr;
+ UINTN row, col;
+ tem_char_t *data;
+ int i;
+
+ (void)conout->QueryMode(conout, conout->Mode->Mode, &col, &row);
+
+ /* reduce clear line on bottom row by one to prevent autoscroll */
+ if (row - 1 == da->row && da->col == 0 && da->width == col)
+ da->width--;
+
+ data = (tem_char_t *)da->data;
+ attr = EFI_TEXT_ATTR(solaris_color_to_efi_color[da->fg_color & 0xf],
+ solaris_color_to_efi_color[da->bg_color & 0xf]);
+ st = conout->SetAttribute(conout, attr);
+ if (EFI_ERROR(st))
+ return;
+ row = da->row;
+ col = da->col;
+ conout->SetCursorPosition(conout, col, row);
+ for (i = 0; i < da->width; i++)
+ efi_cons_efiputchar(data[i]);
}
-/* Home cursor (left top corner), also called from mode command. */
-void
-HO(void)
+static void efi_cons_cursor(struct vis_conscursor *cc)
{
- argc = 1;
- args[0] = args[1] = 1;
- CM();
+ switch (cc->action) {
+ case VIS_HIDE_CURSOR:
+ if (plat_stdout_is_framebuffer())
+ gfx_fb_display_cursor(cc);
+ else
+ plat_tem_hide_prom_cursor();
+ break;
+ case VIS_DISPLAY_CURSOR:
+ if (plat_stdout_is_framebuffer())
+ gfx_fb_display_cursor(cc);
+ else {
+ UINTN row, col;
+ row = cc->row;
+ col = cc->col;
+ conout->SetCursorPosition(conout, col, row);
+ conout->EnableCursor(conout, TRUE);
+ }
+ break;
+ case VIS_GET_CURSOR: { /* only used at startup */
+ uint32_t row, col;
+
+ plat_tem_get_prom_pos(&row, &col);
+ cc->row = row;
+ cc->col = col;
+ }
+ break;
+ }
}
-/* Clear line from current position to end of line */
-static void
-CL(int direction)
+static int
+efi_cons_ioctl(struct console *cp, int cmd, void *data)
{
- int i, len;
- UINTN x, y;
- CHAR16 *line;
+ struct visual_ops *ops = cp->c_private;
- conout->QueryMode(conout, conout->Mode->Mode, &x, &y);
- switch (direction) {
- case 0: /* from cursor to end */
- len = x - curx + 1;
+ switch (cmd) {
+ case VIS_GETIDENTIFIER:
+ memmove(data, ops->ident, sizeof (struct vis_identifier));
break;
- case 1: /* from beginning to cursor */
- len = curx;
+ case VIS_DEVINIT:
+ return (ops->devinit(data));
+ case VIS_CONSCLEAR:
+ return (ops->cons_clear(data));
+ case VIS_CONSCOPY:
+ ops->cons_copy(data);
break;
- case 2: /* entire line */
- default:
- len = x;
+ case VIS_CONSDISPLAY:
+ ops->cons_display(data);
break;
+ case VIS_CONSCURSOR:
+ ops->cons_cursor(data);
+ break;
+ default:
+ return (EINVAL);
}
+ return (0);
+}
- if (cury == y - 1)
- len--;
+static void
+efi_framebuffer_setup(void)
+{
+ int bpp, pos;
- 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;
+ bpp = fls(efifb.fb_mask_red | efifb.fb_mask_green |
+ efifb.fb_mask_blue | efifb.fb_mask_reserved);
- if (direction != 0)
- curs_move(NULL, NULL, 0, cury);
+ gfx_fb.framebuffer_common.mb_type = MULTIBOOT_TAG_TYPE_FRAMEBUFFER;
+ gfx_fb.framebuffer_common.mb_size = sizeof (gfx_fb);
+ gfx_fb.framebuffer_common.framebuffer_addr = efifb.fb_addr;
+ gfx_fb.framebuffer_common.framebuffer_width = efifb.fb_width;
+ gfx_fb.framebuffer_common.framebuffer_height = efifb.fb_height;
+ gfx_fb.framebuffer_common.framebuffer_bpp = bpp;
+ gfx_fb.framebuffer_common.framebuffer_pitch =
+ efifb.fb_stride * (bpp >> 3);
+ gfx_fb.framebuffer_common.framebuffer_type =
+ MULTIBOOT_FRAMEBUFFER_TYPE_RGB;
+ gfx_fb.framebuffer_common.mb_reserved = 0;
- conout->OutputString(conout, line);
- /* restore cursor position */
- curs_move(NULL, NULL, curx, cury);
- free(line);
- end_term();
+ pos = ffs(efifb.fb_mask_red);
+ if (pos != 0)
+ pos--;
+ gfx_fb.u.fb2.framebuffer_red_mask_size = fls(efifb.fb_mask_red >> pos);
+ gfx_fb.u.fb2.framebuffer_red_field_position = pos;
+ pos = ffs(efifb.fb_mask_green);
+ if (pos != 0)
+ pos--;
+ gfx_fb.u.fb2.framebuffer_green_mask_size =
+ fls(efifb.fb_mask_green >> pos);
+ gfx_fb.u.fb2.framebuffer_green_field_position = pos;
+ pos = ffs(efifb.fb_mask_blue);
+ if (pos != 0)
+ pos--;
+ gfx_fb.u.fb2.framebuffer_blue_mask_size =
+ fls(efifb.fb_mask_blue >> pos);
+ gfx_fb.u.fb2.framebuffer_blue_field_position = pos;
}
static void
-get_arg(int c)
+efi_cons_probe(struct console *cp)
{
- if (argc < 0)
- argc = 0;
- args[argc] *= 10;
- args[argc] += c - '0';
-}
+ EFI_STATUS status;
+ UINTN i, max_dim, best_mode, cols, rows;
-/* Emulate basic capabilities of sun-color terminal */
-static void
-efi_term_emu(int c)
-{
- static int ansi_col[] = {
- 0, 4, 2, 6, 1, 5, 3, 7
- };
- int t, i;
+ conout = ST->ConOut;
+ conin = ST->ConIn;
+ cp->c_flags |= C_PRESENTIN | C_PRESENTOUT;
- switch (esc) {
- case 0:
- switch (c) {
- case '\033':
- esc = c;
- break;
- default:
- efi_cons_rawputchar(c);
- break;
+ status = BS->LocateProtocol(&ccontrol_protocol_guid, NULL,
+ (VOID **)&console_control);
+ if (status == EFI_SUCCESS) {
+ BOOLEAN GopUgaExists, StdInLocked;
+ status = console_control->GetMode(console_control,
+ &console_mode, &GopUgaExists, &StdInLocked);
+ } else {
+ console_mode = EfiConsoleControlScreenText;
}
- break;
- case '\033':
- switch (c) {
- case '[':
- esc = c;
- args[0] = 0;
- argc = -1;
- break;
- default:
- bail_out(c);
- break;
+
+ max_dim = best_mode = 0;
+ for (i = 0; i <= conout->Mode->MaxMode ; i++) {
+ status = conout->QueryMode(conout, i, &cols, &rows);
+ if (EFI_ERROR(status))
+ continue;
+ if (cols * rows > max_dim) {
+ max_dim = cols * rows;
+ best_mode = i;
}
- break;
- case '[':
- switch (c) {
- case ';':
- if (argc < 0)
- argc = 0;
- else if (argc + 1 >= MAXARGS)
- bail_out(c);
- else
- args[++argc] = 0;
- break;
- case 'A': /* UP = \E[%dA */
- if (argc == 0) {
- UINTN x, y;
- get_pos(&x, &y);
- args[1] = x + 1;
- args[0] = y - args[0] + 1;
- CM();
- } else
- bail_out(c);
- break;
- case 'B': /* DO = \E[%dB */
- if (argc == 0) {
- UINTN x, y;
- get_pos(&x, &y);
- args[1] = x + 1;
- args[0] = y + args[0] + 1;
- CM();
- } else
- bail_out(c);
- break;
- case 'C': /* RI = \E[%dC */
- if (argc == 0) {
- UINTN x, y;
- get_pos(&x, &y);
- args[1] = args[0] + 1;
- args[0] = y + 1;
- CM();
- } else
- bail_out(c);
- 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 'K':
- if (argc < 0)
- CL(0);
- else if (argc == 0)
- switch (args[0]) {
- case 0:
- case 1:
- case 2:
- CL(args[0]);
- break;
- default:
- bail_out(c);
}
- else
- bail_out(c);
- break;
- case 'm':
- if (argc < 0) {
- fg_c = DEFAULT_FGCOLOR;
- bg_c = DEFAULT_BGCOLOR;
+ if (max_dim > 0)
+ conout->SetMode(conout, best_mode);
+ status = conout->QueryMode(conout, best_mode, &cols, &rows);
+ if (EFI_ERROR(status)) {
+ setenv("screen-#rows", "24", 1);
+ setenv("screen-#cols", "80", 1);
+ } else {
+ char env[8];
+ sprintf(env, "%u", (unsigned)rows);
+ setenv("screen-#rows", env, 1);
+ sprintf(env, "%u", (unsigned)cols);
+ setenv("screen-#cols", env, 1);
}
- 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 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;
+
+ if (efi_find_framebuffer(&efifb)) {
+ console_mode = EfiConsoleControlScreenText;
+ cp->c_private = &text_ops;
+ } else {
+ efi_framebuffer_setup();
+ console_mode = EfiConsoleControlScreenGraphics;
+ cp->c_private = &fb_ops;
}
- }
- 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;
- }
+
+ if (console_control != NULL)
+ (void)console_control->SetMode(console_control, console_mode);
+
+ /* some firmware enables the cursor when switching modes */
+ conout->EnableCursor(conout, FALSE);
}
-void
-efi_cons_putchar(struct console *cp __attribute((unused)), int c)
+static int
+efi_cons_init(struct console *cp, int arg __unused)
{
-#ifdef TERM_EMU
- efi_term_emu(c);
-#else
- efi_cons_rawputchar(c);
+ EFI_STATUS status;
+ int rc;
+
+ conout->SetAttribute(conout, EFI_TEXT_ATTR(DEFAULT_FGCOLOR,
+ DEFAULT_BGCOLOR));
+ memset(keybuf, 0, KEYBUFSZ);
+#if 0
+ status = BS->OpenProtocol(ST->ConsoleInHandle, &simple_input_ex_guid,
+ (void**)&coninex, IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
#endif
+ coninex = NULL;
+
+ gfx_framework_init(&fb_ops);
+ rc = tem_info_init(cp);
+
+ if (rc == 0 && tem == NULL) {
+ tem = tem_init();
+ if (tem != NULL)
+ tem_activate(tem, B_TRUE);
+ }
+
+ if (tem == NULL)
+ panic("Failed to set up console terminal");
+
+ return 0;
}
-int
-efi_cons_getchar(struct console *cp __attribute((unused)))
+static void
+efi_cons_putchar(struct console *cp __unused, int c)
{
- EFI_INPUT_KEY key;
+ uint8_t buf = c;
+
+ /* make sure we have some console output, support for panic() */
+ if (tem == NULL)
+ efi_cons_efiputchar(c);
+ else
+ tem_write(tem, &buf, sizeof (buf));
+}
+
+static int
+efi_cons_getchar(struct console *cp __unused)
+{
+ EFI_INPUT_KEY key, *kp;
+ EFI_KEY_DATA key_data;
EFI_STATUS status;
UINTN junk;
int i, c;
for (i = 0; i < KEYBUFSZ; i++) {
@@ -506,18 +546,31 @@
keybuf[i] = 0;
return (c);
}
}
- /* Try to read a key stroke. We wait for one if none is pending. */
+ if (coninex != NULL) {
+ status = coninex->ReadKeyStrokeEx(coninex, &key_data);
+ if (status == EFI_NOT_READY) {
+ BS->WaitForEvent(1, &coninex->WaitForKeyEx, &junk);
+ status = coninex->ReadKeyStrokeEx(coninex, &key_data);
+ }
+ kp = &key_data.Key;
+ } else {
status = conin->ReadKeyStroke(conin, &key);
if (status == EFI_NOT_READY) {
BS->WaitForEvent(1, &conin->WaitForKey, &junk);
status = conin->ReadKeyStroke(conin, &key);
}
+ kp = &key;
+ }
- switch (key.ScanCode) {
+ if (status != EFI_SUCCESS) {
+ return (-1);
+ }
+
+ switch (kp->ScanCode) {
case 0x1: /* UP */
keybuf[0] = '[';
keybuf[1] = 'A';
return (0x1b); /* esc */
case 0x2: /* DOWN */
@@ -535,55 +588,40 @@
case 0x17: /* ESC */
return (0x1b); /* esc */
}
/* this can return */
- return (key.UnicodeChar);
+ return (kp->UnicodeChar);
}
-int
-efi_cons_poll(struct console *cp __attribute((unused)))
+static int
+efi_cons_poll(struct console *cp __unused)
{
int i;
for (i = 0; i < KEYBUFSZ; i++) {
if (keybuf[i] != 0)
return (1);
}
/* This can clear the signaled state. */
+ if (coninex != NULL)
+ return (BS->CheckEvent(coninex->WaitForKeyEx) == EFI_SUCCESS);
+ else
return (BS->CheckEvent(conin->WaitForKey) == EFI_SUCCESS);
}
/* Plain direct access to EFI OutputString(). */
void
efi_cons_efiputchar(int c)
{
CHAR16 buf[2];
+ EFI_STATUS status;
- /*
- * translate box chars to unicode
- */
- switch (c) {
- /* single frame */
- case 0xb3: buf[0] = BOXDRAW_VERTICAL; break;
- case 0xbf: buf[0] = BOXDRAW_DOWN_LEFT; break;
- case 0xc0: buf[0] = BOXDRAW_UP_RIGHT; break;
- case 0xc4: buf[0] = BOXDRAW_HORIZONTAL; break;
- case 0xda: buf[0] = BOXDRAW_DOWN_RIGHT; break;
- case 0xd9: buf[0] = BOXDRAW_UP_LEFT; break;
-
- /* double frame */
- case 0xba: buf[0] = BOXDRAW_DOUBLE_VERTICAL; break;
- case 0xbb: buf[0] = BOXDRAW_DOUBLE_DOWN_LEFT; break;
- case 0xbc: buf[0] = BOXDRAW_DOUBLE_UP_LEFT; break;
- case 0xc8: buf[0] = BOXDRAW_DOUBLE_UP_RIGHT; break;
- case 0xc9: buf[0] = BOXDRAW_DOUBLE_DOWN_RIGHT; break;
- case 0xcd: buf[0] = BOXDRAW_DOUBLE_HORIZONTAL; break;
-
- default:
buf[0] = c;
- }
buf[1] = 0; /* terminate string */
+ status = conout->TestString(conout, buf);
+ if (EFI_ERROR(status))
+ buf[0] = '?';
conout->OutputString(conout, buf);
}