summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorToomas Soome <tsoome@me.com>2018-12-01 22:31:08 +0200
committerHans Rosenfeld <hans.rosenfeld@joyent.com>2019-01-07 10:11:18 +0100
commit9890ff8357a674572254e0be06b175a1e8eab4b0 (patch)
tree3b4b3a2b61f0cd74bd99b547f6e87c2688b4e122
parentf33b666290305a2b2c134d23cbd1e70e06bf36fd (diff)
downloadillumos-joyent-9890ff8357a674572254e0be06b175a1e8eab4b0.tar.gz
10028 loader: implement framebuffer console
10029 common/font: create shared font.c 10030 import pnglite into usr/src/common/pnglite 8918 loader.efi: add vesa edid support 10031 loader: import tem for loader console 10032 loader: implement tem utf-8 support 10033 ficl: add simple gfx words 10034 loader: use term-drawrect for menu frame 10035 loader: add alpha blending for gfx_fb 10036 ficl: add fb-putimage 10037 loader: add illumos.png logo 10038 loader: replace gop and vesa with framebuffer 10039 loader: build rules for new font setup 10040 loader: gfx use GOP Blt() function in visual_io callbacks Reviewed by: Robert Mustacchi <rm@joyent.com> Reviewed by: Gergő Mihály Doma <domag02@gmail.com> Approved by: Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
-rw-r--r--usr/src/boot/lib/libstand/pager.c19
-rw-r--r--usr/src/boot/sys/boot/Makefile.inc32
-rw-r--r--usr/src/boot/sys/boot/common/bootstrap.h3
-rw-r--r--usr/src/boot/sys/boot/common/console.c7
-rw-r--r--usr/src/boot/sys/boot/common/gfx_fb.c1575
-rw-r--r--usr/src/boot/sys/boot/common/gfx_fb.h115
-rw-r--r--usr/src/boot/sys/boot/common/help.common185
-rwxr-xr-xusr/src/boot/sys/boot/common/linenoise/linenoise.c2
-rw-r--r--usr/src/boot/sys/boot/common/module.c130
-rw-r--r--usr/src/boot/sys/boot/common/multiboot2.c138
-rw-r--r--usr/src/boot/sys/boot/common/tem.c2848
-rw-r--r--usr/src/boot/sys/boot/efi/Makefile.inc1
-rw-r--r--usr/src/boot/sys/boot/efi/include/eficon.h258
-rw-r--r--usr/src/boot/sys/boot/efi/libefi/Makefile.com18
-rw-r--r--usr/src/boot/sys/boot/efi/libefi/efi_console.c950
-rw-r--r--usr/src/boot/sys/boot/efi/loader/Makefile.com29
-rw-r--r--usr/src/boot/sys/boot/efi/loader/comconsole.c11
-rw-r--r--usr/src/boot/sys/boot/efi/loader/efi_main.c38
-rw-r--r--usr/src/boot/sys/boot/efi/loader/framebuffer.c366
-rw-r--r--usr/src/boot/sys/boot/efi/loader/main.c17
-rw-r--r--usr/src/boot/sys/boot/forth/Makefile.inc1
-rw-r--r--usr/src/boot/sys/boot/forth/frames.4th61
-rw-r--r--usr/src/boot/sys/boot/forth/illumos.pngbin0 -> 11979 bytes
-rw-r--r--usr/src/boot/sys/boot/forth/logo-illumos.4th9
-rw-r--r--usr/src/boot/sys/boot/i386/gptzfsboot/zfsboot.c2
-rw-r--r--usr/src/boot/sys/boot/i386/libi386/Makefile23
-rw-r--r--usr/src/boot/sys/boot/i386/libi386/comconsole.c11
-rw-r--r--usr/src/boot/sys/boot/i386/libi386/linux.c3
-rw-r--r--usr/src/boot/sys/boot/i386/libi386/multiboot.c4
-rw-r--r--usr/src/boot/sys/boot/i386/libi386/nullconsole.c17
-rw-r--r--usr/src/boot/sys/boot/i386/libi386/spinconsole.c46
-rw-r--r--usr/src/boot/sys/boot/i386/libi386/vbe.c813
-rw-r--r--usr/src/boot/sys/boot/i386/libi386/vbe.h145
-rw-r--r--usr/src/boot/sys/boot/i386/libi386/vidconsole.c1259
-rw-r--r--usr/src/boot/sys/boot/i386/loader/Makefile13
-rw-r--r--usr/src/boot/sys/boot/i386/loader/chain.c2
-rw-r--r--usr/src/boot/sys/boot/i386/loader/main.c6
-rw-r--r--usr/src/boot/sys/boot/libficl/Makefile.com6
-rw-r--r--usr/src/boot/sys/boot/ofw/common/main.c2
-rw-r--r--usr/src/boot/sys/boot/uboot/common/main.c2
-rw-r--r--usr/src/boot/sys/boot/userboot/userboot/main.c2
-rw-r--r--usr/src/boot/sys/cddl/boot/zfs/zfsimpl.h8
-rw-r--r--usr/src/boot/sys/sys/font.h137
-rw-r--r--usr/src/boot/sys/sys/sysmacros.h6
-rw-r--r--usr/src/boot/sys/sys/tem.h74
-rw-r--r--usr/src/boot/sys/sys/tem_impl.h286
-rw-r--r--usr/src/boot/sys/sys/types.h4
-rw-r--r--usr/src/common/ficl/ficlplatform/pager.c2
-rw-r--r--usr/src/common/ficl/loader.c121
-rw-r--r--usr/src/common/ficl/main.c4
-rw-r--r--usr/src/common/ficl/tools.c2
-rw-r--r--usr/src/common/font/font.c569
-rw-r--r--usr/src/common/pnglite/THIRDPARTYLICENSE26
-rw-r--r--usr/src/common/pnglite/THIRDPARTYLICENSE.descrip1
-rw-r--r--usr/src/common/pnglite/pnglite.c620
-rw-r--r--usr/src/common/pnglite/pnglite.h169
-rw-r--r--usr/src/common/vga/vgasubr.c (renamed from usr/src/uts/common/io/vgasubr.c)57
-rw-r--r--usr/src/lib/libficl/Makefile.com12
-rw-r--r--usr/src/man/man5/loader.58
-rw-r--r--usr/src/pkg/manifests/system-boot-loader.mf3
-rw-r--r--usr/src/uts/common/Makefile.rules8
-rw-r--r--usr/src/uts/common/sys/consplat.h1
-rw-r--r--usr/src/uts/common/sys/vgareg.h8
-rw-r--r--usr/src/uts/common/sys/vgasubr.h45
-rw-r--r--usr/src/uts/common/sys/visual_io.h43
65 files changed, 9910 insertions, 1473 deletions
diff --git a/usr/src/boot/lib/libstand/pager.c b/usr/src/boot/lib/libstand/pager.c
index a966b0bd79..a916ea3cb6 100644
--- a/usr/src/boot/lib/libstand/pager.c
+++ b/usr/src/boot/lib/libstand/pager.c
@@ -1,4 +1,4 @@
-/*-
+/*
* Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
* All rights reserved.
*
@@ -28,7 +28,6 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
#include "stand.h"
#include <string.h>
@@ -36,8 +35,10 @@ __FBSDID("$FreeBSD$");
static int p_maxlines = -1;
static int p_freelines;
-static char *pager_prompt1 = " --more-- <space> page down <enter> line down <q> quit ";
-static char *pager_blank = " ";
+static char *pager_prompt1 = \
+ " --more-- <space> page down <enter> line down <q> quit ";
+static char *pager_blank = \
+ " ";
/*
* 'open' the pager
@@ -47,9 +48,9 @@ pager_open(void)
{
int nlines;
char *cp, *lp;
-
+
nlines = 24; /* sensible default */
- if ((cp = getenv("LINES")) != NULL) {
+ if ((cp = getenv("screen-#rows")) != NULL) {
nlines = strtol(cp, &lp, 0);
}
@@ -85,11 +86,11 @@ pager_output(const char *cp)
if (cp == NULL)
return(0);
-
+
for (;;) {
if (*cp == 0)
return(0);
-
+
putchar(*cp); /* always emit character */
if (*(cp++) == '\n') { /* got a newline? */
@@ -134,7 +135,7 @@ pager_file(const char *fname)
size_t hmuch;
int fd;
int result;
-
+
if ((fd = open(fname, O_RDONLY)) == -1) {
printf("can't open '%s': %s\n", fname, strerror(errno));
return(-1);
diff --git a/usr/src/boot/sys/boot/Makefile.inc b/usr/src/boot/sys/boot/Makefile.inc
index 17088d782d..cf4f1681f2 100644
--- a/usr/src/boot/sys/boot/Makefile.inc
+++ b/usr/src/boot/sys/boot/Makefile.inc
@@ -1,11 +1,31 @@
-# $FreeBSD$
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
-SSP_CFLAGS=
+#
+# Copyright 2017 Toomas Soome <tsoome@me.com>
+#
-.if ${MACHINE_CPUARCH} == "arm"
+# Default Console font setup.
+# We want it to be the same as kernel.
+# We build compressed, stripped down version of the default font, so we have
+# bare minimum for case we can not load font from the OS root.
+
+FONT= 8x16
+FONT_SRC= ter-u16n.bdf
+FONT_DIR= $(SRC)/data/consfonts
+
+#.if ${MACHINE_CPUARCH} == "arm"
# Do not generate movt/movw, because the relocation fixup for them does not
# translate to the -Bsymbolic -pie format required by self_reloc() in loader(8).
# Also, the fpu is not available in a standalone environment.
-CFLAGS.clang+= -mllvm -arm-use-movt=0
-CFLAGS.clang+= -mfpu=none
-.endif
+#CFLAGS.clang+= -mllvm -arm-use-movt=0
+#CFLAGS.clang+= -mfpu=none
+#.endif
diff --git a/usr/src/boot/sys/boot/common/bootstrap.h b/usr/src/boot/sys/boot/common/bootstrap.h
index ed95d140b2..97d86bed57 100644
--- a/usr/src/boot/sys/boot/common/bootstrap.h
+++ b/usr/src/boot/sys/boot/common/bootstrap.h
@@ -108,11 +108,13 @@ struct console
void (*c_out)(struct console *, int); /* emit c */
int (*c_in)(struct console *); /* wait for and return input */
int (*c_ready)(struct console *); /* return nonzer if input waiting */
+ int (*c_ioctl)(struct console *, int, void *);
void *c_private; /* private data */
};
extern struct console *consoles[];
void cons_probe(void);
void cons_mode(int);
+void autoload_font(void);
/*
* Plug-and-play enumerator/configurator interface.
@@ -236,6 +238,7 @@ void file_addmetadata(struct preloaded_file *fp, int type, size_t size, void *p)
int file_addmodule(struct preloaded_file *fp, char *modname, int version,
struct kernel_module **newmp);
void build_environment_module(void);
+void build_font_module(void);
vm_offset_t bi_copyenv(vm_offset_t);
/* MI module loaders */
diff --git a/usr/src/boot/sys/boot/common/console.c b/usr/src/boot/sys/boot/common/console.c
index 5693e819c9..34488a886f 100644
--- a/usr/src/boot/sys/boot/common/console.c
+++ b/usr/src/boot/sys/boot/common/console.c
@@ -58,13 +58,13 @@ cons_probe(void)
/* Do all console probes */
for (cons = 0; consoles[cons] != NULL; cons++) {
consoles[cons]->c_flags = 0;
- consoles[cons]->c_probe(consoles[cons]);
+ consoles[cons]->c_probe(consoles[cons]);
}
/* Now find the first working one */
active = -1;
for (cons = 0; consoles[cons] != NULL && active == -1; cons++) {
consoles[cons]->c_flags = 0;
- consoles[cons]->c_probe(consoles[cons]);
+ consoles[cons]->c_probe(consoles[cons]);
if (consoles[cons]->c_flags == (C_PRESENTIN | C_PRESENTOUT))
active = cons;
}
@@ -270,7 +270,8 @@ cons_change(const char *string)
if (active != 0) {
/* If no consoles have initialised we wouldn't see this. */
- printf("console %s failed to initialize\n", consoles[cons]->c_name);
+ printf("console %s failed to initialize\n",
+ consoles[cons]->c_name);
}
}
}
diff --git a/usr/src/boot/sys/boot/common/gfx_fb.c b/usr/src/boot/sys/boot/common/gfx_fb.c
new file mode 100644
index 0000000000..7a41fd242e
--- /dev/null
+++ b/usr/src/boot/sys/boot/common/gfx_fb.c
@@ -0,0 +1,1575 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2016 Toomas Soome <tsoome@me.com>
+ */
+
+/*
+ * Common functions to implement graphical framebuffer support for console.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <stand.h>
+#if defined(EFI)
+#include <efi.h>
+#include <efilib.h>
+#else
+#include <btxv86.h>
+#endif
+#include <sys/tem_impl.h>
+#include <sys/consplat.h>
+#include <sys/visual_io.h>
+#include <sys/multiboot2.h>
+#include <sys/font.h>
+#include <sys/endian.h>
+#include <gfx_fb.h>
+#include <pnglite.h>
+#include <bootstrap.h>
+
+/*
+ * Global framebuffer struct, to be updated with mode changes.
+ */
+multiboot_tag_framebuffer_t gfx_fb;
+
+/* To support setenv, keep track of inverses and colors. */
+static int gfx_inverse = 0;
+static int gfx_inverse_screen = 0;
+static uint8_t gfx_fg = DEFAULT_ANSI_FOREGROUND;
+static uint8_t gfx_bg = DEFAULT_ANSI_BACKGROUND;
+
+static int gfx_fb_cons_clear(struct vis_consclear *);
+static void gfx_fb_cons_copy(struct vis_conscopy *);
+static void gfx_fb_cons_display(struct vis_consdisplay *);
+
+#if defined (EFI)
+static int gfx_gop_cons_clear(uint32_t data, uint32_t width, uint32_t height);
+static void gfx_gop_cons_copy(struct vis_conscopy *);
+static void gfx_gop_cons_display(struct vis_consdisplay *);
+#endif
+static int gfx_bm_cons_clear(uint32_t data, uint32_t width, uint32_t height);
+static void gfx_bm_cons_copy(struct vis_conscopy *);
+static void gfx_bm_cons_display(struct vis_consdisplay *);
+
+/*
+ * Set default operations to use bitmap based implementation.
+ * In case of UEFI, if GOP is available, we will switch to GOP based
+ * implementation.
+ *
+ * Also note, for UEFI we do attempt to boost the execution by setting
+ * Task Priority Level (TPL) to TPL_NOTIFY, which is highest priority
+ * usable in application.
+ */
+struct gfx_fb_ops {
+ int (*gfx_cons_clear)(uint32_t, uint32_t, uint32_t);
+ void (*gfx_cons_copy)(struct vis_conscopy *);
+ void (*gfx_cons_display)(struct vis_consdisplay *);
+} gfx_fb_ops = {
+ .gfx_cons_clear = gfx_bm_cons_clear,
+ .gfx_cons_copy = gfx_bm_cons_copy,
+ .gfx_cons_display = gfx_bm_cons_display
+};
+
+/*
+ * Translate platform specific FB address.
+ */
+static uint8_t *
+gfx_get_fb_address(void)
+{
+#if defined(EFI)
+ return ((uint8_t *)(uintptr_t)
+ gfx_fb.framebuffer_common.framebuffer_addr);
+#else
+ return ((uint8_t *)PTOV((uint32_t)
+ gfx_fb.framebuffer_common.framebuffer_addr & 0xffffffff));
+#endif
+}
+
+/*
+ * Generic platform callbacks for tem.
+ */
+void
+plat_tem_get_prom_font_size(int *charheight, int *windowtop)
+{
+ *charheight = 0;
+ *windowtop = 0;
+}
+
+void
+plat_tem_get_colors(uint8_t *fg, uint8_t *bg)
+{
+ *fg = gfx_fg;
+ *bg = gfx_bg;
+}
+
+void
+plat_tem_get_inverses(int *inverse, int *inverse_screen)
+{
+ *inverse = gfx_inverse;
+ *inverse_screen = gfx_inverse_screen;
+}
+
+/*
+ * Utility function to parse gfx mode line strings.
+ */
+bool
+gfx_parse_mode_str(char *str, int *x, int *y, int *depth)
+{
+ char *p, *end;
+
+ errno = 0;
+ p = str;
+ *x = strtoul(p, &end, 0);
+ if (*x == 0 || errno != 0)
+ return (false);
+ if (*end != 'x')
+ return (false);
+ p = end + 1;
+ *y = strtoul(p, &end, 0);
+ if (*y == 0 || errno != 0)
+ return (false);
+ if (*end != 'x') {
+ *depth = -1; /* auto select */
+ } else {
+ p = end + 1;
+ *depth = strtoul(p, &end, 0);
+ if (*depth == 0 || errno != 0 || *end != '\0')
+ return (false);
+ }
+
+ return (true);
+}
+
+/*
+ * Support for color mapping.
+ */
+uint32_t
+gfx_fb_color_map(uint8_t index)
+{
+ uint8_t c;
+ int pos, size;
+ uint32_t color;
+
+ if (gfx_fb.framebuffer_common.framebuffer_type !=
+ MULTIBOOT_FRAMEBUFFER_TYPE_RGB) {
+ if (index < nitems (solaris_color_to_pc_color))
+ return (solaris_color_to_pc_color[index]);
+ else
+ return (index);
+ }
+
+ c = cmap4_to_24.red[index];
+ pos = gfx_fb.u.fb2.framebuffer_red_field_position;
+ size = gfx_fb.u.fb2.framebuffer_red_mask_size;
+ color = ((c >> (8 - size)) & ((1 << size) - 1)) << pos;
+
+ c = cmap4_to_24.green[index];
+ pos = gfx_fb.u.fb2.framebuffer_green_field_position;
+ size = gfx_fb.u.fb2.framebuffer_green_mask_size;
+ color |= ((c >> (8 - size)) & ((1 << size) - 1)) << pos;
+
+ c = cmap4_to_24.blue[index];
+ pos = gfx_fb.u.fb2.framebuffer_blue_field_position;
+ size = gfx_fb.u.fb2.framebuffer_blue_mask_size;
+ color |= ((c >> (8 - size)) & ((1 << size) - 1)) << pos;
+
+ return (color);
+}
+
+static bool
+color_name_to_ansi(const char *name, int *val)
+{
+ if (strcasecmp(name, "black") == 0) {
+ *val = ANSI_COLOR_BLACK;
+ return (true);
+ }
+ if (strcasecmp(name, "red") == 0) {
+ *val = ANSI_COLOR_RED;
+ return (true);
+ }
+ if (strcasecmp(name, "green") == 0) {
+ *val = ANSI_COLOR_GREEN;
+ return (true);
+ }
+ if (strcasecmp(name, "yellow") == 0) {
+ *val = ANSI_COLOR_YELLOW;
+ return (true);
+ }
+ if (strcasecmp(name, "blue") == 0) {
+ *val = ANSI_COLOR_BLUE;
+ return (true);
+ }
+ if (strcasecmp(name, "magenta") == 0) {
+ *val = ANSI_COLOR_MAGENTA;
+ return (true);
+ }
+ if (strcasecmp(name, "cyan") == 0) {
+ *val = ANSI_COLOR_CYAN;
+ return (true);
+ }
+ if (strcasecmp(name, "white") == 0) {
+ *val = ANSI_COLOR_WHITE;
+ return (true);
+ }
+ return (false);
+}
+
+/* Callback to check and set colors */
+static int
+gfx_set_colors(struct env_var *ev, int flags, const void *value)
+{
+ int val = 0;
+ char buf[2];
+ const void *evalue;
+
+ if (value == NULL)
+ return (CMD_OK);
+
+ if (color_name_to_ansi(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;
+ }
+
+ /* invalid value? */
+ if (val < 0 || val > 7) {
+ printf("Allowed values are either ansi color name or "
+ "number from range [0-7].\n");
+ return (CMD_OK);
+ }
+
+ if (strcmp(ev->ev_name, "tem.fg_color") == 0) {
+ /* is it already set? */
+ if (gfx_fg == val)
+ return (CMD_OK);
+ gfx_fg = val;
+ }
+ if (strcmp(ev->ev_name, "tem.bg_color") == 0) {
+ /* is it already set? */
+ if (gfx_bg == val)
+ return (CMD_OK);
+ gfx_bg = val;
+ }
+ env_setenv(ev->ev_name, flags | EV_NOHOOK, evalue, NULL, NULL);
+ plat_cons_update_mode(-1);
+ return (CMD_OK);
+}
+
+/* Callback to check and set inverses */
+static int
+gfx_set_inverses(struct env_var *ev, int flags, const void *value)
+{
+ int t, f;
+
+ if (value == NULL)
+ return (CMD_OK);
+
+ t = strcmp(value, "true");
+ f = strcmp(value, "false");
+
+ /* invalid value? */
+ if (t != 0 && f != 0)
+ return (CMD_OK);
+
+ if (strcmp(ev->ev_name, "tem.inverse") == 0) {
+ /* is it already set? */
+ if (gfx_inverse == (t == 0))
+ return (CMD_OK);
+ gfx_inverse = (t == 0);
+ }
+ if (strcmp(ev->ev_name, "tem.inverse-screen") == 0) {
+ /* is it already set? */
+ if (gfx_inverse_screen == (t == 0))
+ return (CMD_OK);
+ gfx_inverse_screen = (t == 0);
+ }
+ env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
+ plat_cons_update_mode(-1);
+ return (CMD_OK);
+}
+
+/*
+ * Initialize gfx framework.
+ */
+void
+gfx_framework_init(struct visual_ops *fb_ops)
+{
+ int rc;
+ char *env, buf[2];
+#if defined (EFI)
+ extern EFI_GRAPHICS_OUTPUT *gop;
+
+ if (gop != NULL) {
+ gfx_fb_ops.gfx_cons_clear = gfx_gop_cons_clear;
+ gfx_fb_ops.gfx_cons_copy = gfx_gop_cons_copy;
+ gfx_fb_ops.gfx_cons_display = gfx_gop_cons_display;
+ }
+#endif
+
+ /* Add visual io callbacks */
+ fb_ops->cons_clear = gfx_fb_cons_clear;
+ fb_ops->cons_copy = gfx_fb_cons_copy;
+ fb_ops->cons_display = gfx_fb_cons_display;
+
+ /* set up tem inverse controls */
+ env = getenv("tem.inverse");
+ if (env != NULL) {
+ if (strcmp(env, "true") == 0)
+ gfx_inverse = 1;
+ unsetenv("tem.inverse");
+ }
+
+ env = getenv("tem.inverse-screen");
+ if (env != NULL) {
+ if (strcmp(env, "true") == 0)
+ gfx_inverse_screen = 1;
+ unsetenv("tem.inverse-screen");
+ }
+
+ if (gfx_inverse)
+ env = "true";
+ else
+ env = "false";
+
+ env_setenv("tem.inverse", EV_VOLATILE, env, gfx_set_inverses,
+ env_nounset);
+
+ if (gfx_inverse_screen)
+ env = "true";
+ else
+ env = "false";
+
+ env_setenv("tem.inverse-screen", EV_VOLATILE, env, gfx_set_inverses,
+ env_nounset);
+
+ /* set up tem color controls */
+ env = getenv("tem.fg_color");
+ if (env != NULL) {
+ rc = (int) strtol(env, NULL, 0);
+ if (rc >= 0 && rc <= 7)
+ gfx_fg = rc;
+ unsetenv("tem.fg_color");
+ }
+
+ env = getenv("tem.bg_color");
+ if (env != NULL) {
+ rc = (int) strtol(env, NULL, 0);
+ if (rc >= 0 && rc <= 7)
+ gfx_bg = rc;
+ unsetenv("tem.bg_color");
+ }
+
+ snprintf(buf, sizeof (buf), "%d", gfx_fg);
+ env_setenv("tem.fg_color", EV_VOLATILE, buf, gfx_set_colors,
+ env_nounset);
+ snprintf(buf, sizeof (buf), "%d", gfx_bg);
+ env_setenv("tem.bg_color", EV_VOLATILE, buf, gfx_set_colors,
+ env_nounset);
+}
+
+/*
+ * visual io callbacks.
+ */
+
+#if defined (EFI)
+static int
+gfx_gop_cons_clear(uint32_t data, uint32_t width, uint32_t height)
+{
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
+ EFI_STATUS status;
+ extern EFI_GRAPHICS_OUTPUT *gop;
+
+ BltBuffer = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)&data;
+
+ status = gop->Blt(gop, BltBuffer, EfiBltVideoFill, 0, 0,
+ 0, 0, width, height, 0);
+
+ if (EFI_ERROR(status))
+ return (1);
+ else
+ return (0);
+}
+#endif
+
+static int
+gfx_bm_cons_clear(uint32_t data, uint32_t width, uint32_t height)
+{
+ uint8_t *fb, *fb8;
+ uint32_t *fb32, pitch;
+ uint16_t *fb16;
+ uint32_t i, j;
+
+ fb = gfx_get_fb_address();
+ pitch = gfx_fb.framebuffer_common.framebuffer_pitch;
+
+ switch (gfx_fb.framebuffer_common.framebuffer_bpp) {
+ case 8: /* 8 bit */
+ for (i = 0; i < height; i++) {
+ (void) memset(fb + i * pitch, data, pitch);
+ }
+ break;
+ case 15:
+ case 16: /* 16 bit */
+ for (i = 0; i < height; i++) {
+ fb16 = (uint16_t *)(fb + i * pitch);
+ for (j = 0; j < width; j++)
+ fb16[j] = (uint16_t)(data & 0xffff);
+ }
+ break;
+ case 24: /* 24 bit */
+ for (i = 0; i < height; i++) {
+ fb8 = fb + i * pitch;
+ for (j = 0; j < pitch; j += 3) {
+ fb8[j] = (data >> 16) & 0xff;
+ fb8[j+1] = (data >> 8) & 0xff;
+ fb8[j+2] = data & 0xff;
+ }
+ }
+ break;
+ case 32: /* 32 bit */
+ for (i = 0; i < height; i++) {
+ fb32 = (uint32_t *)(fb + i * pitch);
+ for (j = 0; j < width; j++)
+ fb32[j] = data;
+ }
+ break;
+ default:
+ return (1);
+ }
+
+ return (0);
+}
+
+static int
+gfx_fb_cons_clear(struct vis_consclear *ca)
+{
+ uint32_t data, width, height;
+ int ret;
+#if defined (EFI)
+ EFI_TPL tpl;
+#endif
+
+ data = gfx_fb_color_map(ca->bg_color);
+ width = gfx_fb.framebuffer_common.framebuffer_width;
+ height = gfx_fb.framebuffer_common.framebuffer_height;
+
+#if defined (EFI)
+ tpl = BS->RaiseTPL(TPL_NOTIFY);
+#endif
+ ret = gfx_fb_ops.gfx_cons_clear(data, width, height);
+#if defined (EFI)
+ BS->RestoreTPL(tpl);
+#endif
+ return (ret);
+}
+
+#if defined (EFI)
+static void
+gfx_gop_cons_copy(struct vis_conscopy *ma)
+{
+ UINTN width, height;
+ extern EFI_GRAPHICS_OUTPUT *gop;
+
+ width = ma->e_col - ma->s_col + 1;
+ height = ma->e_row - ma->s_row + 1;
+
+ (void) gop->Blt(gop, NULL, EfiBltVideoToVideo, ma->s_col, ma->s_row,
+ ma->t_col, ma->t_row, width, height, 0);
+}
+#endif
+
+static void
+gfx_bm_cons_copy(struct vis_conscopy *ma)
+{
+ uint32_t soffset, toffset;
+ uint32_t width, height;
+ uint8_t *src, *dst, *fb;
+ uint32_t bpp, pitch;
+
+ fb = gfx_get_fb_address();
+ bpp = roundup2(gfx_fb.framebuffer_common.framebuffer_bpp, 8) >> 3;
+ pitch = gfx_fb.framebuffer_common.framebuffer_pitch;
+
+ soffset = ma->s_col * bpp + ma->s_row * pitch;
+ toffset = ma->t_col * bpp + ma->t_row * pitch;
+ src = fb + soffset;
+ dst = fb + toffset;
+ width = (ma->e_col - ma->s_col + 1) * bpp;
+ height = ma->e_row - ma->s_row + 1;
+
+ if (toffset <= soffset) {
+ for (uint32_t i = 0; i < height; i++) {
+ uint32_t increment = i * pitch;
+ (void)memmove(dst + increment, src + increment, width);
+ }
+ } else {
+ for (int i = height - 1; i >= 0; i--) {
+ uint32_t increment = i * pitch;
+ (void)memmove(dst + increment, src + increment, width);
+ }
+ }
+}
+
+static void
+gfx_fb_cons_copy(struct vis_conscopy *ma)
+{
+#if defined (EFI)
+ EFI_TPL tpl;
+
+ tpl = BS->RaiseTPL(TPL_NOTIFY);
+#endif
+
+ gfx_fb_ops.gfx_cons_copy(ma);
+#if defined (EFI)
+ BS->RestoreTPL(tpl);
+#endif
+}
+
+/*
+ * Implements alpha blending for RGBA data, could use pixels for arguments,
+ * but byte stream seems more generic.
+ * The generic alpha blending is:
+ * blend = alpha * fg + (1.0 - alpha) * bg.
+ * Since our alpha is not from range [0..1], we scale appropriately.
+ */
+static uint8_t
+alpha_blend(uint8_t fg, uint8_t bg, uint8_t alpha)
+{
+ uint16_t blend, h, l;
+
+ /* trivial corner cases */
+ if (alpha == 0)
+ return (bg);
+ if (alpha == 0xFF)
+ return (fg);
+ blend = (alpha * fg + (0xFF - alpha) * bg);
+ /* Division by 0xFF */
+ h = blend >> 8;
+ l = blend & 0xFF;
+ if (h + l >= 0xFF)
+ h++;
+ return (h);
+}
+
+/* Copy memory to framebuffer or to memory. */
+static void
+bitmap_cpy(uint8_t *dst, uint8_t *src, uint32_t len, int bpp)
+{
+ uint32_t i;
+ uint8_t a;
+
+ switch (bpp) {
+ case 4:
+ /*
+ * we only implement alpha blending for depth 32,
+ * use memcpy for other cases.
+ */
+ for (i = 0; i < len; i += bpp) {
+ a = src[i+3];
+ dst[i] = alpha_blend(src[i], dst[i], a);
+ dst[i+1] = alpha_blend(src[i+1], dst[i+1], a);
+ dst[i+2] = alpha_blend(src[i+2], dst[i+2], a);
+ dst[i+3] = a;
+ }
+ break;
+ default:
+ (void) memcpy(dst, src, len);
+ break;
+ }
+}
+
+#if defined (EFI)
+static void
+gfx_gop_cons_display(struct vis_consdisplay *da)
+{
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
+ uint32_t size;
+ int bpp;
+ extern EFI_GRAPHICS_OUTPUT *gop;
+
+ bpp = roundup2(gfx_fb.framebuffer_common.framebuffer_bpp, 8) >> 3;
+ size = sizeof (*BltBuffer) * da->width * da->height;
+ BltBuffer = malloc(size);
+ if (BltBuffer == NULL && gfx_get_fb_address() != NULL) {
+ /* Fall back to bitmap implementation */
+ gfx_bm_cons_display(da);
+ return;
+ }
+
+ (void) gop->Blt(gop, BltBuffer, EfiBltVideoToBltBuffer,
+ da->col, da->row, 0, 0, da->width, da->height, 0);
+ bitmap_cpy((void *)BltBuffer, da->data, size, bpp);
+ (void) gop->Blt(gop, BltBuffer, EfiBltBufferToVideo,
+ 0, 0, da->col, da->row, da->width, da->height, 0);
+ free(BltBuffer);
+}
+#endif
+
+static void
+gfx_bm_cons_display(struct vis_consdisplay *da)
+{
+ uint32_t size; /* write size per scanline */
+ uint8_t *fbp; /* fb + calculated offset */
+ int i, bpp, pitch;
+
+ bpp = roundup2(gfx_fb.framebuffer_common.framebuffer_bpp, 8) >> 3;
+ pitch = gfx_fb.framebuffer_common.framebuffer_pitch;
+
+ size = da->width * bpp;
+ fbp = gfx_get_fb_address();
+ fbp += da->col * bpp + da->row * pitch;
+
+ /* write all scanlines in rectangle */
+ for (i = 0; i < da->height; i++) {
+ uint8_t *dest = fbp + i * pitch;
+ uint8_t *src = da->data + i * size;
+ bitmap_cpy(dest, src, size, bpp);
+ }
+}
+
+static void
+gfx_fb_cons_display(struct vis_consdisplay *da)
+{
+#if defined (EFI)
+ EFI_TPL tpl;
+#endif
+
+ /* make sure we will not write past FB */
+ if ((uint32_t)da->col >= gfx_fb.framebuffer_common.framebuffer_width ||
+ (uint32_t)da->row >= gfx_fb.framebuffer_common.framebuffer_height ||
+ (uint32_t)da->col + da->width >
+ gfx_fb.framebuffer_common.framebuffer_width ||
+ (uint32_t)da->row + da->height >
+ gfx_fb.framebuffer_common.framebuffer_height)
+ return;
+
+#if defined (EFI)
+ tpl = BS->RaiseTPL(TPL_NOTIFY);
+#endif
+ gfx_fb_ops.gfx_cons_display(da);
+#if defined (EFI)
+ BS->RestoreTPL(tpl);
+#endif
+}
+
+void
+gfx_fb_display_cursor(struct vis_conscursor *ca)
+{
+ uint32_t fg, bg;
+ uint32_t offset, size, *fb32;
+ uint16_t *fb16;
+ uint8_t *fb8, *fb;
+ uint32_t bpp, pitch;
+#if defined (EFI)
+ EFI_TPL tpl;
+#endif
+
+ fb = gfx_get_fb_address();
+ bpp = roundup2(gfx_fb.framebuffer_common.framebuffer_bpp, 8) >> 3;
+ pitch = gfx_fb.framebuffer_common.framebuffer_pitch;
+
+ size = ca->width * bpp;
+
+ /*
+ * Build cursor image. We are building mirror image of data on
+ * frame buffer by (D xor FG) xor BG.
+ */
+ offset = ca->col * bpp + ca->row * pitch;
+#if defined (EFI)
+ tpl = BS->RaiseTPL(TPL_NOTIFY);
+#endif
+ switch (gfx_fb.framebuffer_common.framebuffer_bpp) {
+ case 8: /* 8 bit */
+ fg = ca->fg_color.mono;
+ bg = ca->bg_color.mono;
+ for (int i = 0; i < ca->height; i++) {
+ fb8 = fb + offset + i * pitch;
+ for (uint32_t j = 0; j < size; j += 1) {
+ fb8[j] = (fb8[j] ^ (fg & 0xff)) ^ (bg & 0xff);
+ }
+ }
+ break;
+ case 15:
+ case 16: /* 16 bit */
+ fg = ca->fg_color.sixteen[0] << 8;
+ fg |= ca->fg_color.sixteen[1];
+ bg = ca->bg_color.sixteen[0] << 8;
+ bg |= ca->bg_color.sixteen[1];
+ for (int i = 0; i < ca->height; i++) {
+ fb16 = (uint16_t *)(fb + offset + i * pitch);
+ for (int j = 0; j < ca->width; j++) {
+ fb16[j] = (fb16[j] ^ (fg & 0xffff)) ^
+ (bg & 0xffff);
+ }
+ }
+ break;
+ case 24: /* 24 bit */
+ fg = ca->fg_color.twentyfour[0] << 16;
+ fg |= ca->fg_color.twentyfour[1] << 8;
+ fg |= ca->fg_color.twentyfour[2];
+ bg = ca->bg_color.twentyfour[0] << 16;
+ bg |= ca->bg_color.twentyfour[1] << 8;
+ bg |= ca->bg_color.twentyfour[2];
+
+ for (int i = 0; i < ca->height; i++) {
+ fb8 = fb + offset + i * pitch;
+ for (uint32_t j = 0; j < size; j += 3) {
+ fb8[j] = (fb8[j] ^ ((fg >> 16) & 0xff)) ^
+ ((bg >> 16) & 0xff);
+ fb8[j+1] = (fb8[j+1] ^ ((fg >> 8) & 0xff)) ^
+ ((bg >> 8) & 0xff);
+ fb8[j+2] = (fb8[j+2] ^ (fg & 0xff)) ^
+ (bg & 0xff);
+ }
+ }
+ break;
+ case 32: /* 32 bit */
+ fg = ca->fg_color.twentyfour[0] << 16;
+ fg |= ca->fg_color.twentyfour[1] << 8;
+ fg |= ca->fg_color.twentyfour[2];
+ bg = ca->bg_color.twentyfour[0] << 16;
+ bg |= ca->bg_color.twentyfour[1] << 8;
+ bg |= ca->bg_color.twentyfour[2];
+ for (int i = 0; i < ca->height; i++) {
+ fb32 = (uint32_t *)(fb + offset + i * pitch);
+ for (int j = 0; j < ca->width; j++)
+ fb32[j] = (fb32[j] ^ fg) ^ bg;
+ }
+ break;
+ }
+#if defined (EFI)
+ BS->RestoreTPL(tpl);
+#endif
+}
+
+/*
+ * Public graphics primitives.
+ */
+
+static int
+isqrt(int num)
+{
+ int res = 0;
+ int bit = 1 << 30;
+
+ /* "bit" starts at the highest power of four <= the argument. */
+ while (bit > num)
+ bit >>= 2;
+
+ while (bit != 0) {
+ if (num >= res + bit) {
+ num -= res + bit;
+ res = (res >> 1) + bit;
+ } else
+ res >>= 1;
+ bit >>= 2;
+ }
+ return (res);
+}
+
+/* set pixel in framebuffer using gfx coordinates */
+void
+gfx_fb_setpixel(uint32_t x, uint32_t y)
+{
+ uint32_t c, offset, pitch, bpp;
+ uint8_t *fb;
+ text_color_t fg, bg;
+
+ if (plat_stdout_is_framebuffer() == 0)
+ return;
+
+ tem_get_colors((tem_vt_state_t)tems.ts_active, &fg, &bg);
+ c = gfx_fb_color_map(fg);
+
+ if (x >= gfx_fb.framebuffer_common.framebuffer_width ||
+ y >= gfx_fb.framebuffer_common.framebuffer_height)
+ return;
+
+ fb = gfx_get_fb_address();
+ pitch = gfx_fb.framebuffer_common.framebuffer_pitch;
+ bpp = roundup2(gfx_fb.framebuffer_common.framebuffer_bpp, 8) >> 3;
+
+ offset = y * pitch + x * bpp;
+ switch (gfx_fb.framebuffer_common.framebuffer_bpp) {
+ case 8:
+ fb[offset] = c & 0xff;
+ break;
+ case 15:
+ case 16:
+ *(uint16_t *)(fb + offset) = c & 0xffff;
+ break;
+ case 24:
+ fb[offset] = (c >> 16) & 0xff;
+ fb[offset + 1] = (c >> 8) & 0xff;
+ fb[offset + 2] = c & 0xff;
+ break;
+ case 32:
+ *(uint32_t *)(fb + offset) = c;
+ break;
+ }
+}
+
+/*
+ * draw rectangle in framebuffer using gfx coordinates.
+ * The function is borrowed from fbsd vt_fb.c
+ */
+void
+gfx_fb_drawrect(uint32_t x1, uint32_t y1, uint32_t x2, uint32_t y2,
+ uint32_t fill)
+{
+ uint32_t x, y;
+
+ if (plat_stdout_is_framebuffer() == 0)
+ return;
+
+ for (y = y1; y <= y2; y++) {
+ if (fill || (y == y1) || (y == y2)) {
+ for (x = x1; x <= x2; x++)
+ gfx_fb_setpixel(x, y);
+ } else {
+ gfx_fb_setpixel(x1, y);
+ gfx_fb_setpixel(x2, y);
+ }
+ }
+}
+
+void
+gfx_fb_line(uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1, uint32_t wd)
+{
+ int dx, sx, dy, sy;
+ int err, e2, x2, y2, ed, width;
+
+ if (plat_stdout_is_framebuffer() == 0)
+ return;
+
+ width = wd;
+ sx = x0 < x1? 1 : -1;
+ sy = y0 < y1? 1 : -1;
+ dx = x1 > x0? x1 - x0 : x0 - x1;
+ dy = y1 > y0? y1 - y0 : y0 - y1;
+ err = dx + dy;
+ ed = dx + dy == 0 ? 1: isqrt(dx * dx + dy * dy);
+
+ for (;;) {
+ gfx_fb_setpixel(x0, y0);
+ e2 = err;
+ x2 = x0;
+ if ((e2 << 1) >= -dx) { /* x step */
+ e2 += dy;
+ y2 = y0;
+ while (e2 < ed * width &&
+ (y1 != (uint32_t)y2 || dx > dy)) {
+ y2 += sy;
+ gfx_fb_setpixel(x0, y2);
+ e2 += dx;
+ }
+ if (x0 == x1)
+ break;
+ e2 = err;
+ err -= dy;
+ x0 += sx;
+ }
+ if ((e2 << 1) <= dy) { /* y step */
+ e2 = dx-e2;
+ while (e2 < ed * width &&
+ (x1 != (uint32_t)x2 || dx < dy)) {
+ x2 += sx;
+ gfx_fb_setpixel(x2, y0);
+ e2 += dy;
+ }
+ if (y0 == y1)
+ break;
+ err += dx;
+ y0 += sy;
+ }
+ }
+}
+
+/*
+ * quadratic Bézier curve limited to gradients without sign change.
+ */
+void
+gfx_fb_bezier(uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1, uint32_t x2,
+ uint32_t y2, uint32_t wd)
+{
+ int sx, sy, xx, yy, xy, width;
+ int dx, dy, err, curvature;
+ int i;
+
+ if (plat_stdout_is_framebuffer() == 0)
+ return;
+
+ width = wd;
+ sx = x2 - x1;
+ sy = y2 - y1;
+ xx = x0 - x1;
+ yy = y0 - y1;
+ curvature = xx*sy - yy*sx;
+
+ if (sx*sx + sy*sy > xx*xx+yy*yy) {
+ x2 = x0;
+ x0 = sx + x1;
+ y2 = y0;
+ y0 = sy + y1;
+ curvature = -curvature;
+ }
+ if (curvature != 0) {
+ xx += sx;
+ sx = x0 < x2? 1 : -1;
+ xx *= sx;
+ yy += sy;
+ sy = y0 < y2? 1 : -1;
+ yy *= sy;
+ xy = (xx*yy) << 1;
+ xx *= xx;
+ yy *= yy;
+ if (curvature * sx * sy < 0) {
+ xx = -xx;
+ yy = -yy;
+ xy = -xy;
+ curvature = -curvature;
+ }
+ dx = 4 * sy * curvature * (x1 - x0) + xx - xy;
+ dy = 4 * sx * curvature * (y0 - y1) + yy - xy;
+ xx += xx;
+ yy += yy;
+ err = dx + dy + xy;
+ do {
+ for (i = 0; i <= width; i++)
+ gfx_fb_setpixel(x0 + i, y0);
+ if (x0 == x2 && y0 == y2)
+ return; /* last pixel -> curve finished */
+ y1 = 2 * err < dx;
+ if (2 * err > dy) {
+ x0 += sx;
+ dx -= xy;
+ dy += yy;
+ err += dy;
+ }
+ if (y1 != 0) {
+ y0 += sy;
+ dy -= xy;
+ dx += xx;
+ err += dx;
+ }
+ } while (dy < dx ); /* gradient negates -> algorithm fails */
+ }
+ gfx_fb_line(x0, y0, x2, y2, width);
+}
+
+/*
+ * draw rectangle using terminal coordinates and current foreground color.
+ */
+void
+gfx_term_drawrect(uint32_t ux1, uint32_t uy1, uint32_t ux2, uint32_t uy2)
+{
+ int x1, y1, x2, y2;
+ int xshift, yshift;
+ int width, i;
+ uint32_t vf_width, vf_height;
+
+ if (plat_stdout_is_framebuffer() == 0)
+ return;
+
+ vf_width = tems.ts_font.vf_width;
+ vf_height = tems.ts_font.vf_height;
+ width = vf_width / 4; /* line width */
+ xshift = (vf_width - width) / 2;
+ yshift = (vf_height - width) / 2;
+ /* Terminal coordinates start from (1,1) */
+ ux1--;
+ uy1--;
+ ux2--;
+ uy2--;
+
+ /* mark area used in tem */
+ tem_image_display(tems.ts_active, uy1 - 1, ux1 - 1, uy2, ux2);
+
+ /*
+ * Draw horizontal lines width points thick, shifted from outer edge.
+ */
+ x1 = (ux1 + 1) * vf_width + tems.ts_p_offset.x;
+ y1 = uy1 * vf_height + tems.ts_p_offset.y + yshift;
+ x2 = ux2 * vf_width + tems.ts_p_offset.x;
+ gfx_fb_drawrect(x1, y1, x2, y1 + width, 1);
+ y2 = uy2 * vf_height + tems.ts_p_offset.y;
+ y2 += vf_height - yshift - width;
+ gfx_fb_drawrect(x1, y2, x2, y2 + width, 1);
+
+ /*
+ * Draw vertical lines width points thick, shifted from outer edge.
+ */
+ x1 = ux1 * vf_width + tems.ts_p_offset.x + xshift;
+ y1 = uy1 * vf_height + tems.ts_p_offset.y;
+ y1 += vf_height;
+ y2 = uy2 * vf_height + tems.ts_p_offset.y;
+ gfx_fb_drawrect(x1, y1, x1 + width, y2, 1);
+ x1 = ux2 * vf_width + tems.ts_p_offset.x;
+ x1 += vf_width - xshift - width;
+ gfx_fb_drawrect(x1, y1, x1 + width, y2, 1);
+
+ /* Draw upper left corner. */
+ x1 = ux1 * vf_width + tems.ts_p_offset.x + xshift;
+ y1 = uy1 * vf_height + tems.ts_p_offset.y;
+ y1 += vf_height;
+
+ x2 = ux1 * vf_width + tems.ts_p_offset.x;
+ x2 += vf_width;
+ y2 = uy1 * vf_height + tems.ts_p_offset.y + yshift;
+ for (i = 0; i <= width; i++)
+ gfx_fb_bezier(x1 + i, y1, x1 + i, y2 + i, x2, y2 + i, width-i);
+
+ /* Draw lower left corner. */
+ x1 = ux1 * vf_width + tems.ts_p_offset.x;
+ x1 += vf_width;
+ y1 = uy2 * vf_height + tems.ts_p_offset.y;
+ y1 += vf_height - yshift;
+ x2 = ux1 * vf_width + tems.ts_p_offset.x + xshift;
+ y2 = uy2 * vf_height + tems.ts_p_offset.y;
+ for (i = 0; i <= width; i++)
+ gfx_fb_bezier(x1, y1 - i, x2 + i, y1 - i, x2 + i, y2, width-i);
+
+ /* Draw upper right corner. */
+ x1 = ux2 * vf_width + tems.ts_p_offset.x;
+ y1 = uy1 * vf_height + tems.ts_p_offset.y + yshift;
+ x2 = ux2 * vf_width + tems.ts_p_offset.x;
+ x2 += vf_width - xshift - width;
+ y2 = uy1 * vf_height + tems.ts_p_offset.y;
+ y2 += vf_height;
+ for (i = 0; i <= width; i++)
+ gfx_fb_bezier(x1, y1 + i, x2 + i, y1 + i, x2 + i, y2, width-i);
+
+ /* Draw lower right corner. */
+ x1 = ux2 * vf_width + tems.ts_p_offset.x;
+ y1 = uy2 * vf_height + tems.ts_p_offset.y;
+ y1 += vf_height - yshift;
+ x2 = ux2 * vf_width + tems.ts_p_offset.x;
+ x2 += vf_width - xshift - width;
+ y2 = uy2 * vf_height + tems.ts_p_offset.y;
+ for (i = 0; i <= width; i++)
+ gfx_fb_bezier(x1, y1 - i, x2 + i, y1 - i, x2 + i, y2, width-i);
+}
+
+int
+gfx_fb_putimage(png_t *png)
+{
+ struct vis_consdisplay da;
+ uint32_t i, j, height, width, color;
+ int bpp;
+ uint8_t r, g, b, a, *p;
+
+ if (plat_stdout_is_framebuffer() == 0 ||
+ png->color_type != PNG_TRUECOLOR_ALPHA) {
+ return (1);
+ }
+
+ bpp = roundup2(gfx_fb.framebuffer_common.framebuffer_bpp, 8) >> 3;
+ width = png->width;
+ height = png->height;
+ da.width = png->width;
+ da.height = png->height;
+ da.col = gfx_fb.framebuffer_common.framebuffer_width -
+ tems.ts_p_offset.x;
+ da.col -= da.width;
+ da.row = gfx_fb.framebuffer_common.framebuffer_height -
+ tems.ts_p_offset.y;
+ da.row -= da.height;
+
+ /*
+ * mark area used in tem
+ */
+ tem_image_display(tems.ts_active, da.row / tems.ts_font.vf_height - 1,
+ da.col / tems.ts_font.vf_width - 1,
+ tems.ts_c_dimension.height - 1,
+ tems.ts_c_dimension.width - 1);
+
+ da.data = malloc(width * height * bpp);
+ if (da.data == NULL)
+ return (1);
+
+ /*
+ * Build image for our framebuffer.
+ */
+ for (i = 0; i < height * width * png->bpp; i += png->bpp) {
+ r = png->image[i];
+ g = png->image[i+1];
+ b = png->image[i+2];
+ a = png->image[i+3];
+
+ j = i / png->bpp * bpp;
+ color = r >> (8 - gfx_fb.u.fb2.framebuffer_red_mask_size)
+ << gfx_fb.u.fb2.framebuffer_red_field_position;
+ color |= g >> (8 - gfx_fb.u.fb2.framebuffer_green_mask_size)
+ << gfx_fb.u.fb2.framebuffer_green_field_position;
+ color |= b >> (8 - gfx_fb.u.fb2.framebuffer_blue_mask_size)
+ << gfx_fb.u.fb2.framebuffer_blue_field_position;
+
+ switch (gfx_fb.framebuffer_common.framebuffer_bpp) {
+ case 8: {
+ uint32_t best, dist, k;
+ int diff;
+
+ color = 0;
+ best = 256 * 256 * 256;
+ for (k = 0; k < 16; k++) {
+ diff = r - cmap4_to_24.red[k];
+ dist = diff * diff;
+ diff = g - cmap4_to_24.green[k];
+ dist += diff * diff;
+ diff = b - cmap4_to_24.blue[k];
+ dist += diff * diff;
+
+ if (dist < best) {
+ color = k;
+ best = dist;
+ if (dist == 0)
+ break;
+ }
+ }
+ da.data[j] = solaris_color_to_pc_color[color];
+ break;
+ }
+ case 15:
+ case 16:
+ *(uint16_t *)(da.data+j) = color;
+ break;
+ case 24:
+ p = (uint8_t *)&color;
+ da.data[j] = p[0];
+ da.data[j+1] = p[1];
+ da.data[j+2] = p[2];
+ break;
+ case 32:
+ color |= a << 24;
+ *(uint32_t *)(da.data+j) = color;
+ break;
+ }
+ }
+
+ gfx_fb_cons_display(&da);
+ free(da.data);
+ return (0);
+}
+
+static int
+load_mapping(int fd, struct font *fp, int n)
+{
+ size_t i, size;
+ ssize_t rv;
+ struct font_map *mp;
+
+ if (fp->vf_map_count[n] == 0)
+ return (0);
+
+ size = fp->vf_map_count[n] * sizeof (*mp);
+ mp = malloc(size);
+ if (mp == NULL)
+ return (ENOMEM);
+ fp->vf_map[n] = mp;
+
+ rv = read(fd, mp, size);
+ if (rv < 0 || (size_t)rv != size) {
+ free(fp->vf_map[n]);
+ fp->vf_map[n] = NULL;
+ return (EIO);
+ }
+
+ for (i = 0; i < fp->vf_map_count[n]; i++) {
+ mp[i].font_src = be32toh(mp[i].font_src);
+ mp[i].font_dst = be16toh(mp[i].font_dst);
+ mp[i].font_len = be16toh(mp[i].font_len);
+ }
+ return (0);
+}
+
+/* Load font from file. */
+static bitmap_data_t *
+load_font(char *path)
+{
+ int fd, i;
+ uint32_t glyphs;
+ struct font_header fh;
+ struct fontlist *fl;
+ bitmap_data_t *bp = NULL;
+ struct font *fp;
+ size_t size;
+ ssize_t rv;
+
+ /* Get our entry from the font list. */
+ STAILQ_FOREACH(fl, &fonts, font_next) {
+ if (strcmp(fl->font_name, path) == 0)
+ break;
+ }
+ if (fl == NULL)
+ return (NULL); /* Should not happen. */
+ bp = fl->font_data;
+ if (bp->font != NULL)
+ return (bp);
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ return (NULL);
+ }
+
+ size = sizeof (fh);
+ rv = read(fd, &fh, size);
+ if (rv < 0 || (size_t)rv != size) {
+ bp = NULL;
+ goto done;
+ }
+ if (memcmp(fh.fh_magic, FONT_HEADER_MAGIC, sizeof (fh.fh_magic)) != 0) {
+ bp = NULL;
+ goto done;
+ }
+ if ((fp = calloc(1, sizeof (struct font))) == NULL) {
+ bp = NULL;
+ goto done;
+ }
+ for (i = 0; i < VFNT_MAPS; i++)
+ fp->vf_map_count[i] = be32toh(fh.fh_map_count[i]);
+
+ glyphs = be32toh(fh.fh_glyph_count);
+ fp->vf_width = fh.fh_width;
+ fp->vf_height = fh.fh_height;
+
+ bp->uncompressed_size = howmany(bp->width, 8) * bp->height * glyphs;
+ size = bp->uncompressed_size;
+ if ((fp->vf_bytes = malloc(size)) == NULL)
+ goto free_done;
+
+ rv = read(fd, fp->vf_bytes, size);
+ if (rv < 0 || (size_t)rv != size)
+ goto free_done;
+ for (i = 0; i < VFNT_MAPS; i++) {
+ if (load_mapping(fd, fp, i) != 0)
+ goto free_done;
+ }
+ bp->font = fp;
+
+ /*
+ * Release previously loaded entry. We can do this now, as
+ * the new font is loaded. Note, there can be no console
+ * output till the new font is in place and tem is notified.
+ * We do need to keep fl->font_data for glyph dimensions.
+ */
+ STAILQ_FOREACH(fl, &fonts, font_next) {
+ if (fl->font_data->width == bp->width &&
+ fl->font_data->height == bp->height)
+ continue;
+
+ if (fl->font_data->font != NULL) {
+ for (i = 0; i < VFNT_MAPS; i++)
+ free(fl->font_data->font->vf_map[i]);
+
+ /* Unset vf_bytes pointer in tem. */
+ if (tems.ts_font.vf_bytes ==
+ fl->font_data->font->vf_bytes) {
+ tems.ts_font.vf_bytes = NULL;
+ }
+ free(fl->font_data->font->vf_bytes);
+ free(fl->font_data->font);
+ fl->font_data->font = NULL;
+ fl->font_data->uncompressed_size = 0;
+ fl->font_flags = FONT_AUTO;
+ }
+ }
+
+ /* free the uncompressed builtin font data in tem. */
+ free(tems.ts_font.vf_bytes);
+ tems.ts_font.vf_bytes = NULL;
+
+done:
+ close(fd);
+ return (bp);
+
+free_done:
+ for (i = 0; i < VFNT_MAPS; i++)
+ free(fp->vf_map[i]);
+ free(fp->vf_bytes);
+ free(fp);
+ bp = NULL;
+ goto done;
+}
+
+
+struct name_entry {
+ char *n_name;
+ SLIST_ENTRY(name_entry) n_entry;
+};
+
+SLIST_HEAD(name_list, name_entry);
+
+/* Read font names from index file. */
+static struct name_list *
+read_list(char *fonts)
+{
+ struct name_list *nl;
+ struct name_entry *np;
+ char buf[PATH_MAX];
+ int fd, len;
+
+ fd = open(fonts, O_RDONLY);
+ if (fd < 0)
+ return (NULL);
+
+ nl = malloc(sizeof (*nl));
+ if (nl == NULL) {
+ close(fd);
+ return (nl);
+ }
+
+ SLIST_INIT(nl);
+ while ((len = fgetstr(buf, sizeof (buf), fd)) > 0) {
+ np = malloc(sizeof (*np));
+ if (np == NULL) {
+ close(fd);
+ return (nl); /* return what we have */
+ }
+ np->n_name = strdup(buf);
+ if (np->n_name == NULL) {
+ free(np);
+ close(fd);
+ return (nl); /* return what we have */
+ }
+ SLIST_INSERT_HEAD(nl, np, n_entry);
+ }
+ close(fd);
+ return (nl);
+}
+
+/*
+ * Read the font properties and insert new entry into the list.
+ * The font list is built in descending order.
+ */
+static bool
+insert_font(char *name)
+{
+ struct font_header fh;
+ struct fontlist *fp, *previous, *entry, *next;
+ size_t size;
+ ssize_t rv;
+ int fd;
+ char *font_name;
+
+ fd = open(name, O_RDONLY);
+ if (fd < 0)
+ return (false);
+ rv = read(fd, &fh, sizeof (fh));
+ close(fd);
+ if (rv < 0 || (size_t)rv != sizeof (fh))
+ return (false);
+
+ if (memcmp(fh.fh_magic, FONT_HEADER_MAGIC, sizeof (fh.fh_magic)) != 0)
+ return (false);
+
+ font_name = strdup(name);
+ if (font_name == NULL)
+ return (false);
+
+ /*
+ * If we have an entry with the same glyph dimensions, just replace
+ * the file name. We only support unique dimensions.
+ */
+ STAILQ_FOREACH(entry, &fonts, font_next) {
+ if (fh.fh_width == entry->font_data->width &&
+ fh.fh_height == entry->font_data->height) {
+ free(entry->font_name);
+ entry->font_name = font_name;
+ return (true);
+ }
+ }
+
+ fp = calloc(sizeof (*fp), 1);
+ if (fp == NULL) {
+ free(font_name);
+ return (false);
+ }
+ fp->font_data = calloc(sizeof (*fp->font_data), 1);
+ if (fp->font_data == NULL) {
+ free(font_name);
+ free(fp);
+ return (false);
+ }
+ fp->font_name = font_name;
+ fp->font_flags = FONT_AUTO;
+ fp->font_load = load_font;
+ fp->font_data->width = fh.fh_width;
+ fp->font_data->height = fh.fh_height;
+
+ if (STAILQ_EMPTY(&fonts)) {
+ STAILQ_INSERT_HEAD(&fonts, fp, font_next);
+ return (true);
+ }
+
+ previous = NULL;
+ size = fp->font_data->width * fp->font_data->height;
+
+ STAILQ_FOREACH(entry, &fonts, font_next) {
+ /* Should fp be inserted before the entry? */
+ if (size >
+ entry->font_data->width * entry->font_data->height) {
+ if (previous == NULL) {
+ STAILQ_INSERT_HEAD(&fonts, fp, font_next);
+ } else {
+ STAILQ_INSERT_AFTER(&fonts, previous, fp,
+ font_next);
+ }
+ return (true);
+ }
+ next = STAILQ_NEXT(entry, font_next);
+ if (next == NULL ||
+ size > next->font_data->width * next->font_data->height) {
+ STAILQ_INSERT_AFTER(&fonts, entry, fp, font_next);
+ return (true);
+ }
+ previous = entry;
+ }
+ return (true);
+}
+
+static int
+font_set(struct env_var *ev __unused, int flags __unused, const void *value)
+{
+ struct fontlist *fl, *tmp;
+ char *eptr;
+ unsigned long x = 0, y = 0;
+
+ /*
+ * Attempt to extract values from "XxY" string. In case of error,
+ * we have unmaching glyph dimensions and will just output the
+ * available values.
+ */
+ if (value != NULL) {
+ x = strtoul(value, &eptr, 10);
+ if (*eptr == 'x')
+ y = strtoul(eptr + 1, &eptr, 10);
+ }
+ STAILQ_FOREACH(fl, &fonts, font_next) {
+ if (fl->font_data->width == x && fl->font_data->height == y)
+ break;
+ }
+ if (fl != NULL) {
+ /* Reset any FONT_MANUAL flag. */
+ STAILQ_FOREACH(tmp, &fonts, font_next)
+ tmp->font_flags = FONT_AUTO;
+
+ fl->font_flags = FONT_MANUAL;
+ /* Trigger tem update. */
+ tems.update_font = true;
+ plat_cons_update_mode(-1);
+ return (CMD_OK);
+ }
+
+ printf("Available fonts:\n");
+ STAILQ_FOREACH(fl, &fonts, font_next) {
+ printf(" %dx%d\n", fl->font_data->width,
+ fl->font_data->height);
+ }
+ return (CMD_OK);
+}
+
+void
+autoload_font(void)
+{
+ struct name_list *nl;
+ struct name_entry *np;
+
+ nl = read_list("/boot/fonts/fonts.dir");
+ if (nl == NULL)
+ return;
+
+ while (!SLIST_EMPTY(nl)) {
+ np = SLIST_FIRST(nl);
+ SLIST_REMOVE_HEAD(nl, n_entry);
+ if (insert_font(np->n_name) == false)
+ printf("failed to add font: %s\n", np->n_name);
+ free(np->n_name);
+ free(np);
+ }
+
+ unsetenv("screen-font");
+ env_setenv("screen-font", EV_VOLATILE, NULL, font_set, env_nounset);
+ /* Trigger tem update. */
+ tems.update_font = true;
+ plat_cons_update_mode(-1);
+}
+
+COMMAND_SET(load_font, "loadfont", "load console font from file", command_font);
+
+static int
+command_font(int argc, char *argv[])
+{
+ int i, rc = CMD_OK;
+ struct fontlist *fl;
+ bitmap_data_t *bd;
+
+ if (argc > 2) {
+ printf("Usage: loadfont [file.fnt]\n");
+ return (CMD_ERROR);
+ }
+
+ if (argc == 2) {
+ char *name = argv[1];
+
+ if (insert_font(name) == false) {
+ printf("loadfont error: failed to load: %s\n", name);
+ return (CMD_ERROR);
+ }
+
+ bd = load_font(name);
+ if (bd == NULL) {
+ printf("loadfont error: failed to load: %s\n", name);
+ return (CMD_ERROR);
+ }
+
+ /* Get the font list entry and mark it manually loaded. */
+ STAILQ_FOREACH(fl, &fonts, font_next) {
+ if (strcmp(fl->font_name, name) == 0)
+ fl->font_flags = FONT_MANUAL;
+ }
+ tems.update_font = true;
+ plat_cons_update_mode(-1);
+ return (CMD_OK);
+ }
+
+ if (argc == 1) {
+ /*
+ * Walk entire font list, release any loaded font, and set
+ * autoload flag. If the font list is empty, the tem will
+ * get the builtin default.
+ */
+ STAILQ_FOREACH(fl, &fonts, font_next) {
+ if (fl->font_data->font != NULL) {
+ /* Note the tem is releasing font bytes */
+ for (i = 0; i < VFNT_MAPS; i++)
+ free(fl->font_data->font->vf_map[i]);
+ free(fl->font_data->font);
+ fl->font_data->font = NULL;
+ fl->font_data->uncompressed_size = 0;
+ fl->font_flags = FONT_AUTO;
+ }
+ }
+ tems.update_font = true;
+ plat_cons_update_mode(-1);
+ }
+ return (rc);
+}
diff --git a/usr/src/boot/sys/boot/common/gfx_fb.h b/usr/src/boot/sys/boot/common/gfx_fb.h
new file mode 100644
index 0000000000..5161383759
--- /dev/null
+++ b/usr/src/boot/sys/boot/common/gfx_fb.h
@@ -0,0 +1,115 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 Toomas Soome <tsoome@me.com>
+ */
+
+#ifndef _GFX_FB_H
+#define _GFX_FB_H
+
+#include <stdbool.h>
+#include <sys/visual_io.h>
+#include <sys/multiboot2.h>
+#include <pnglite.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define EDID_MAGIC { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 }
+
+struct edid_header {
+ uint8_t header[8]; /* fixed header pattern */
+ uint16_t manufacturer_id;
+ uint16_t product_code;
+ uint32_t serial_number;
+ uint8_t week_of_manufacture;
+ uint8_t year_of_manufacture;
+ uint8_t version;
+ uint8_t revision;
+};
+
+struct edid_basic_display_parameters {
+ uint8_t video_input_parameters;
+ uint8_t max_horizontal_image_size;
+ uint8_t max_vertical_image_size;
+ uint8_t display_gamma;
+ uint8_t supported_features;
+};
+
+struct edid_chromaticity_coordinates {
+ uint8_t red_green_lo;
+ uint8_t blue_white_lo;
+ uint8_t red_x_hi;
+ uint8_t red_y_hi;
+ uint8_t green_x_hi;
+ uint8_t green_y_hi;
+ uint8_t blue_x_hi;
+ uint8_t blue_y_hi;
+ uint8_t white_x_hi;
+ uint8_t white_y_hi;
+};
+
+struct edid_detailed_timings {
+ uint16_t pixel_clock;
+ uint8_t horizontal_active_lo;
+ uint8_t horizontal_blanking_lo;
+ uint8_t horizontal_hi;
+ uint8_t vertical_active_lo;
+ uint8_t vertical_blanking_lo;
+ uint8_t vertical_hi;
+ uint8_t horizontal_sync_offset_lo;
+ uint8_t horizontal_sync_pulse_width_lo;
+ uint8_t vertical_sync_lo;
+ uint8_t sync_hi;
+ uint8_t horizontal_image_size_lo;
+ uint8_t vertical_image_size_lo;
+ uint8_t image_size_hi;
+ uint8_t horizontal_border;
+ uint8_t vertical_border;
+ uint8_t features;
+};
+
+struct vesa_edid_info {
+ struct edid_header header;
+ struct edid_basic_display_parameters display;
+#define EDID_FEATURE_PREFERRED_TIMING_MODE (1 << 1)
+ struct edid_chromaticity_coordinates chromaticity;
+ uint8_t established_timings_1;
+ uint8_t established_timings_2;
+ uint8_t manufacturer_reserved_timings;
+ uint16_t standard_timings[8];
+ struct edid_detailed_timings detailed_timings[4];
+ uint8_t number_of_extensions;
+ uint8_t checksum;
+} __packed;
+
+extern multiboot_tag_framebuffer_t gfx_fb;
+
+void gfx_framework_init(struct visual_ops *);
+uint32_t gfx_fb_color_map(uint8_t);
+void gfx_fb_display_cursor(struct vis_conscursor *);
+void gfx_fb_setpixel(uint32_t, uint32_t);
+void gfx_fb_drawrect(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
+void gfx_term_drawrect(uint32_t, uint32_t, uint32_t, uint32_t);
+void gfx_fb_line(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
+void gfx_fb_bezier(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t,
+ uint32_t);
+void plat_cons_update_mode(int);
+int gfx_fb_putimage(png_t *);
+
+bool gfx_parse_mode_str(char *, int *, int *, int *);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GFX_FB_H */
diff --git a/usr/src/boot/sys/boot/common/help.common b/usr/src/boot/sys/boot/common/help.common
index ead8511faf..7342c95a55 100644
--- a/usr/src/boot/sys/boot/common/help.common
+++ b/usr/src/boot/sys/boot/common/help.common
@@ -80,8 +80,19 @@
will print the current device.
################################################################################
+# Tframebuffer DManage framebuffer setup
+
+ framebuffer on | off | get | list [depth] | set <display or mode number>
+
+ Switch framebuffer mode on or off, get current mode, list available
+ modes or set mode by using either display resolution or framebuffer
+ mode number. If the system does not provide display resolution via
+ EDID, the default resolution will be set to 800x600. If depth is not
+ specified, the best depth is used.
+
+################################################################################
# Tload DLoad a kernel or module
-
+
load [-t <type>] <filename> [arguments]
Loads the module contained in <filename> into memory. If no other
@@ -172,45 +183,40 @@
Sets the default set of kernel boot filename(s). It may be overridden
by setting the bootfile variable to a semicolon-separated list of
filenames, each of which will be searched for in the module_path
- directories. The default bootfile set is "kernel".
-
-################################################################################
-# Tset Sboot_askname DPrompt for root device
-
- set boot_askname
-
- Instructs the kernel to prompt the user for the name of the root device
- when the kernel is booted.
+ directories. The default bootfile set is "unix".
################################################################################
-# Tset Sboot_cdrom DMount root file system from CD-ROM
+# Tset Sboot_ask DPrompt for configuration information
- set boot_cdrom
+ set boot_ask
- Instructs the kernel to try to mount the root file system from CD-ROM.
+ Instructs the kernel to prompt the user for the configuration
+ information when the kernel is booted.
################################################################################
-# Tset Sboot_ddb DDrop to the kernel debugger (DDB)
+# Tset Sboot_debug DDrop to the kernel debugger (kmdb)
- set boot_ddb
+ set boot_debug
- Instructs the kernel to start in the DDB debugger, rather than
- proceeding to initialize when booted.
+ Instructs the kernel to start in the kmdb debugger, rather than
+ proceeding to initialize when booted. Can only be used when boot_kmdb
+ is set.
################################################################################
-# Tset Sboot_dfltroot DUse default root file system
+# Tset Sboot_kmdb DStart the kernel debugger (kmdb)
- set boot_dfltroot
+ set boot_kmdb
- Instructs the kernel to mount the statically compiled-in root
- file system.
+ Instructs the kernel to start the kmdb debugger and then continue
+ with normal boot.
################################################################################
-# Tset Sboot_gdb DSelect gdb-remote mode for the kernel debugger
+# Tset Sboot_reconfigure DInitaiate reconfiguration boot
- set boot_gdb
+ set boot_reconfigure
- Selects gdb-remote mode for the kernel debugger by default.
+ The system will probe all attached hardware devices and configure
+ the logical namespace in /dev.
################################################################################
# Tset Sboot_multicons DUse multiple consoles
@@ -222,50 +228,23 @@
by the conscontrol(8) utility.
################################################################################
-# Tset Sboot_mute DMute the console
-
- set boot_mute
-
- All console output is suppressed when console is muted.
- In a running system, the state of console muting can be
- manipulated by the conscontrol(8) utility.
-
-################################################################################
-# Tset Sboot_pause DPause after each line during device probing
-
- set boot_pause
-
- During the device probe, pause after each line is printed.
-
-################################################################################
-# Tset Sboot_serial DUse serial console
-
- set boot_serial
-
- Force the use of a serial console even when an internal console
- is present.
-
-################################################################################
-# Tset Sboot_single DStart system in single-user mode
+# Tset Sboot_single DBoot into the single user mode
set boot_single
- Prevents the kernel from initiating a multi-user startup; instead,
- a single-user mode will be entered when the kernel has finished
- device probes.
+ Boots only to init level 's'.
################################################################################
-# Tset Sboot_verbose DVerbose boot messages
+# Tset Sboot_verbose DBoot with verbose messages enabled
set boot_verbose
- Setting this variable causes extra debugging information to be printed
- by the kernel during the boot phase.
+ Without this setting, the messages are only logged in the system log.
################################################################################
# Tset Sconsole DSet the current console
- set console[=<value>]
+ set console[=<value>[,<value>]]
Sets the current console. If <value> is omitted, a list of valid
consoles will be displayed.
@@ -278,15 +257,6 @@
Selects the default device. See lsdev for available devices.
################################################################################
-# Tset Sinit_path DSet the list of init candidates
-
- set init_path=<path>[:<path>...]
-
- Sets the list of binaries which the kernel will try to run as initial
- process.
-
-
-################################################################################
# Tset Smodule_path DSet the module search path
set module_path=<path>[;<path>...]
@@ -302,12 +272,18 @@
set prompt=<value>
The command prompt is displayed when the loader is waiting for input.
- Variable substitution is performed on the prompt. The default
+ Variable substitution is performed on the prompt. The default
prompt can be set with:
set prompt=\${interpret}
################################################################################
+# Tset Sscreen-font DSet the framebuffer font
+
+ Without the value, will list the currently available list
+ of the fonts.
+
+################################################################################
# Tset Srootdev DSet the root filesystem
set rootdev=<path>
@@ -317,75 +293,6 @@
$rootdev explicitly.
################################################################################
-# Tset Stunables DSet kernel tunable values
-
- Various kernel tunable parameters can be overridden by specifying new
- values in the environment.
-
- set kern.ipc.nmbclusters=<value>
-
- Set the number of mbuf clusters to be allocated. The value
- cannot be set below the default determined when the kernel
- was compiled.
-
- set kern.ipc.nsfbufs=<value> NSFBUFS
-
- Set the number of sendfile buffers to be allocated. This
- overrides the value determined when the kernel was compiled.
-
- set vm.kmem_size=<value> VM_KMEM_SIZE
-
- Sets the size of kernel memory (bytes). This overrides
- the value determined when the kernel was compiled.
-
- set machdep.disable_mtrrs=1
-
- Disable the use of i686 MTRRs (i386 only)
-
- set net.inet.tcp.tcbhashsize=<value> TCBHASHSIZE
-
- Overrides the compile-time set value of TCBHASHSIZE or
- the preset default of 512. Must be a power of 2.
-
- hw.syscons.sc_no_suspend_vtswitch=<value>
-
- Disable VT switching on suspend.
-
- value is 0 (default) or non-zero to enable.
-
- set hw.physmem=<value> MAXMEM (i386 only)
-
- Limits the amount of physical memory space available to
- the system to <value> bytes. <value> may have a k, M or G
- suffix to indicate kilobytes, megabytes and gigabytes
- respectively. Note that the current i386 architecture
- limits this value to 4GB.
-
- On systems where memory cannot be accurately probed,
- this option provides a hint as to the actual size of
- system memory (which will be tested before use).
-
- set hw.{acpi,pci}.host_start_mem=<value>
-
- Sets the lowest address that the pci code will assign
- when it doesn't have other information about the address
- to assign (like from a pci bridge). This is only useful
- in older systems without a pci bridge. Also, it only
- impacts devices that the BIOS doesn't assign to, typically
- CardBus bridges. The default <value> is 0x80000000, but
- some systems need values like 0xf0000000, 0xfc000000 or
- 0xfe000000 may be suitable for older systems (the older
- the system, the higher the number typically should be).
-
- set hw.pci.enable_io_modes=<value>
-
- Enable PCI resources which are left off by some BIOSes
- or are not enabled correctly by the device driver.
-
- value is 1 (default), but this may cause problems with
- some peripherals. Set to 0 to disable.
-
-################################################################################
# Tshow DShow the values of variables
show [<variable>]
@@ -405,12 +312,12 @@
read [-t <value>] [-p <prompt>] [<variable name>]
- The read command reads a line of input from the terminal. If the
+ The read command reads a line of input from the terminal. If the
-t argument is specified, it will return nothing if no input has been
- received after <value> seconds. (Any keypress will cancel the
+ received after <value> seconds. (Any keypress will cancel the
timeout).
- If -p is specified, <prompt> is printed before reading input. No
+ If -p is specified, <prompt> is printed before reading input. No
newline is emitted after the prompt.
If a variable name is supplied, the variable is set to the value read,
@@ -429,6 +336,6 @@
unset <variable name>
If allowed, the named variable's value is discarded and the variable
- is removed.
+ is removed.
################################################################################
diff --git a/usr/src/boot/sys/boot/common/linenoise/linenoise.c b/usr/src/boot/sys/boot/common/linenoise/linenoise.c
index e789a21d3f..871ffb5437 100755
--- a/usr/src/boot/sys/boot/common/linenoise/linenoise.c
+++ b/usr/src/boot/sys/boot/common/linenoise/linenoise.c
@@ -187,7 +187,7 @@ void linenoiseClearScreen(void) {
static int
getColumns(void)
{
- char *columns = getenv("COLUMNS");
+ char *columns = getenv("screen-#cols");
if (columns == NULL)
return (80);
return (strtol(columns, NULL, 0));
diff --git a/usr/src/boot/sys/boot/common/module.c b/usr/src/boot/sys/boot/common/module.c
index 50afdbef7f..243e8e466a 100644
--- a/usr/src/boot/sys/boot/common/module.c
+++ b/usr/src/boot/sys/boot/common/module.c
@@ -1,4 +1,4 @@
-/*-
+/*
* Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
* All rights reserved.
*
@@ -37,6 +37,8 @@
#include <sys/module.h>
#include <sys/queue.h>
#include <sys/stdint.h>
+#include <sys/tem_impl.h>
+#include <sys/font.h>
#include "bootstrap.h"
@@ -103,7 +105,7 @@ command_load(int argc, char *argv[])
{
char *typestr;
int dofile, dokld, ch, error;
-
+
dokld = dofile = 0;
optind = 1;
optreset = 1;
@@ -165,7 +167,7 @@ command_load(int argc, char *argv[])
"warning: KLD '%s' already loaded", argv[1]);
return (CMD_WARN);
}
-
+
return (error == 0 ? CMD_OK : CMD_CRIT);
}
/*
@@ -443,6 +445,7 @@ build_environment_module(void)
return;
}
+ tem_save_state(); /* Ask tem to save it's state in env. */
size = env_get_size();
fp = file_alloc();
@@ -483,6 +486,111 @@ build_environment_module(void)
file_insert_tail(fp);
}
+void
+build_font_module(void)
+{
+ bitmap_data_t *bd;
+ struct font *fd;
+ struct preloaded_file *fp;
+ size_t size;
+ uint32_t checksum;
+ int i;
+ char *name = "console-font";
+ vm_offset_t laddr;
+ struct font_info fi;
+ struct fontlist *fl;
+
+ if (STAILQ_EMPTY(&fonts))
+ return;
+
+ /* We can't load first */
+ if ((file_findfile(NULL, NULL)) == NULL) {
+ printf("Can not load font module: %s\n",
+ "the kernel is not loaded");
+ return;
+ }
+
+ /* helper pointers */
+ bd = NULL;
+ STAILQ_FOREACH(fl, &fonts, font_next) {
+ if (fl->font_data->font != NULL) {
+ bd = fl->font_data;
+ break;
+ }
+ }
+ if (bd == NULL)
+ return;
+ fd = bd->font;
+
+ fi.fi_width = fd->vf_width;
+ checksum = fi.fi_width;
+ fi.fi_height = fd->vf_height;
+ checksum += fi.fi_height;
+ fi.fi_bitmap_size = bd->uncompressed_size;
+ checksum += fi.fi_bitmap_size;
+
+ size = roundup2(sizeof (struct font_info), 8);
+ for (i = 0; i < VFNT_MAPS; i++) {
+ fi.fi_map_count[i] = fd->vf_map_count[i];
+ checksum += fi.fi_map_count[i];
+ size += fd->vf_map_count[i] * sizeof (struct font_map);
+ size += roundup2(size, 8);
+ }
+ size += bd->uncompressed_size;
+
+ fi.fi_checksum = -checksum;
+
+ fp = file_alloc();
+ if (fp != NULL) {
+ fp->f_name = strdup(name);
+ fp->f_type = strdup(name);
+ }
+
+ if (fp == NULL || fp->f_name == NULL || fp->f_type == NULL) {
+ printf("Can not load font module: %s\n",
+ "out of memory");
+ if (fp != NULL)
+ file_discard(fp);
+ return;
+ }
+
+ if (archsw.arch_loadaddr != NULL)
+ loadaddr = archsw.arch_loadaddr(LOAD_MEM, &size, loadaddr);
+
+ if (loadaddr == 0) {
+ printf("Can not load font module: %s\n",
+ "out of memory");
+ file_discard(fp);
+ return;
+ }
+
+ laddr = loadaddr;
+ laddr += archsw.arch_copyin(&fi, laddr, sizeof (struct font_info));
+ laddr = roundup2(laddr, 8);
+
+ /* Copy maps. */
+ for (i = 0; i < VFNT_MAPS; i++) {
+ if (fd->vf_map_count[i] != 0) {
+ laddr += archsw.arch_copyin(fd->vf_map[i], laddr,
+ fd->vf_map_count[i] * sizeof (struct font_map));
+ laddr = roundup2(laddr, 8);
+ }
+ }
+
+ /* Copy the bitmap. */
+ laddr += archsw.arch_copyin(fd->vf_bytes, laddr, fi.fi_bitmap_size);
+
+ /* Looks OK so far; populate control structure */
+ fp->f_loader = -1;
+ fp->f_addr = loadaddr;
+ fp->f_size = laddr - loadaddr;
+
+ /* recognise space consumption */
+ loadaddr = laddr;
+
+ file_insert_tail(fp);
+}
+
/*
* We've been asked to load (fname) as (type), so just suck it in,
* no arguments or anything.
@@ -568,7 +676,7 @@ file_loadraw(const char *fname, char *type, int argc, char **argv, int insert)
/* Add to the list of loaded files */
if (insert != 0)
- file_insert_tail(fp);
+ file_insert_tail(fp);
close(fd);
return(fp);
}
@@ -630,7 +738,7 @@ mod_loadkld(const char *kldname, int argc, char *argv[])
"can't find '%s'", kldname);
return (ENOENT);
}
- /*
+ /*
* Check if KLD already loaded
*/
fp = file_findfile(filename, NULL);
@@ -640,7 +748,7 @@ mod_loadkld(const char *kldname, int argc, char *argv[])
free(filename);
return (0);
}
- for (last_file = preloaded_files;
+ for (last_file = preloaded_files;
last_file != NULL && last_file->f_next != NULL;
last_file = last_file->f_next)
;
@@ -701,7 +809,7 @@ file_findmodule(struct preloaded_file *fp, char *modname,
if (fp == NULL) {
for (fp = preloaded_files; fp; fp = fp->f_next) {
mp = file_findmodule(fp, modname, verinfo);
- if (mp)
+ if (mp)
return (mp);
}
return (NULL);
@@ -715,7 +823,7 @@ file_findmodule(struct preloaded_file *fp, char *modname,
mver = mp->m_version;
if (mver == verinfo->md_ver_preferred)
return (mp);
- if (mver >= verinfo->md_ver_minimum &&
+ if (mver >= verinfo->md_ver_minimum &&
mver <= verinfo->md_ver_maximum &&
mver > bestver) {
best = mp;
@@ -902,7 +1010,7 @@ mod_search_hints(struct moduledir *mdp, const char *modname,
found = 1;
break;
}
- if (ival >= verinfo->md_ver_minimum &&
+ if (ival >= verinfo->md_ver_minimum &&
ival <= verinfo->md_ver_maximum &&
ival > bestver) {
bestver = ival;
@@ -1024,7 +1132,7 @@ struct preloaded_file *
file_alloc(void)
{
struct preloaded_file *fp;
-
+
if ((fp = malloc(sizeof(struct preloaded_file))) != NULL) {
bzero(fp, sizeof(struct preloaded_file));
}
@@ -1038,7 +1146,7 @@ static void
file_insert_tail(struct preloaded_file *fp)
{
struct preloaded_file *cm;
-
+
/* Append to list of loaded file */
fp->f_next = NULL;
if (preloaded_files == NULL) {
diff --git a/usr/src/boot/sys/boot/common/multiboot2.c b/usr/src/boot/sys/boot/common/multiboot2.c
index c0477ecc1a..5b2cb9d397 100644
--- a/usr/src/boot/sys/boot/common/multiboot2.c
+++ b/usr/src/boot/sys/boot/common/multiboot2.c
@@ -34,6 +34,7 @@
#include "libzfs.h"
#include "bootstrap.h"
+#include <sys/consplat.h>
#include <machine/metadata.h>
#include <machine/pc/bios.h>
@@ -42,8 +43,9 @@
#include <bootp.h>
#if !defined(EFI)
-#include "../i386/libi386/libi386.h"
#include "../i386/btx/lib/btxv86.h"
+#include "libi386.h"
+#include "vbe.h"
#else
#include <efi.h>
@@ -195,6 +197,7 @@ multiboot2_loadfile(char *filename, u_int64_t dest,
if (header == NULL)
goto out;
+ have_framebuffer = false;
for (tag = header->mb2_tags; tag->mbh_type != MULTIBOOT_TAG_TYPE_END;
tag = (multiboot_header_tag_t *)((uintptr_t)tag +
roundup2(tag->mbh_size, MULTIBOOT_TAG_ALIGN))) {
@@ -731,6 +734,9 @@ static size_t
mbi_size(struct preloaded_file *fp, char *cmdline)
{
size_t size;
+#if !defined (EFI)
+ extern multiboot_tag_framebuffer_t gfx_fb;
+#endif
size = sizeof (uint32_t) * 2; /* first 2 fields from MBI header */
size += sizeof (multiboot_tag_string_t) + strlen(cmdline) + 1;
@@ -754,9 +760,25 @@ mbi_size(struct preloaded_file *fp, char *cmdline)
size = roundup2(size, MULTIBOOT_TAG_ALIGN);
}
#endif
+
size += biossmap_size(fp);
size = roundup2(size, MULTIBOOT_TAG_ALIGN);
+#if !defined (EFI)
+ if (gfx_fb.framebuffer_common.framebuffer_type ==
+ MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED) {
+ size += sizeof (struct multiboot_tag_framebuffer_common);
+ size += gfx_fb.u.fb1.framebuffer_palette_num_colors *
+ sizeof (multiboot_color_t);
+ } else {
+ size += sizeof (multiboot_tag_framebuffer_t);
+ }
+ size = roundup2(size, MULTIBOOT_TAG_ALIGN);
+
+ size += sizeof (multiboot_tag_vbe_t);
+ size = roundup2(size, MULTIBOOT_TAG_ALIGN);
+#endif
+
if (bootp_response != NULL) {
size += sizeof(multiboot_tag_network_t) + bootp_response_size;
size = roundup2(size, MULTIBOOT_TAG_ALIGN);
@@ -801,6 +823,11 @@ multiboot2_exec(struct preloaded_file *fp)
efi_getdev((void **)(&rootdev), NULL, NULL);
#else
i386_getdev((void **)(&rootdev), NULL, NULL);
+
+ if (have_framebuffer == false) {
+ /* make sure we have text mode */
+ bios_set_text_mode(VGA_TEXT_MODE);
+ }
#endif
mbi = NULL;
@@ -831,6 +858,11 @@ multiboot2_exec(struct preloaded_file *fp)
/* mb_kernel_cmdline() updates the environment. */
build_environment_module();
+ if (have_framebuffer == true) {
+ /* Pass the loaded console font for kernel. */
+ build_font_module();
+ }
+
size = mbi_size(fp, cmdline); /* Get the size for MBI. */
/* Set up the base for mb_malloc. */
@@ -1017,6 +1049,20 @@ multiboot2_exec(struct preloaded_file *fp)
memcpy(tag->mb_dhcpack, bootp_response, bootp_response_size);
}
+#if !defined (EFI)
+ {
+ multiboot_tag_vbe_t *tag;
+ extern multiboot_tag_vbe_t vbestate;
+
+ if (VBE_VALID_MODE(vbestate.vbe_mode)) {
+ tag = (multiboot_tag_vbe_t *)mb_malloc(sizeof(*tag));
+ memcpy(tag, &vbestate, sizeof(*tag));
+ tag->mb_type = MULTIBOOT_TAG_TYPE_VBE;
+ tag->mb_size = sizeof(*tag);
+ }
+ }
+#endif
+
if (rsdp != NULL) {
multiboot_tag_new_acpi_t *ntag;
multiboot_tag_old_acpi_t *otag;
@@ -1059,60 +1105,50 @@ multiboot2_exec(struct preloaded_file *fp)
tag->mb_pointer = (uint32_t)ST;
}
#endif /* __LP64__ */
+#endif /* EFI */
if (have_framebuffer == true) {
multiboot_tag_framebuffer_t *tag;
- int bpp;
- struct efi_fb fb;
- extern int efi_find_framebuffer(struct efi_fb *efifb);
-
- if (efi_find_framebuffer(&fb) == 0) {
- tag = (multiboot_tag_framebuffer_t *)
- mb_malloc(sizeof (*tag));
-
- /*
- * We assume contiguous color bitmap, and use
- * the msb for bits per pixel calculation.
- */
- bpp = fls(fb.fb_mask_red | fb.fb_mask_green |
- fb.fb_mask_blue | fb.fb_mask_reserved);
-
- tag->framebuffer_common.mb_type =
- MULTIBOOT_TAG_TYPE_FRAMEBUFFER;
- tag->framebuffer_common.mb_size =
- sizeof (multiboot_tag_framebuffer_t);
- tag->framebuffer_common.framebuffer_addr = fb.fb_addr;
- tag->framebuffer_common.framebuffer_width = fb.fb_width;
- tag->framebuffer_common.framebuffer_height =
- fb.fb_height;
- tag->framebuffer_common.framebuffer_bpp = bpp;
- /*
- * Pitch is stride * bytes per pixel.
- * Stride is pixels per scanline.
- */
- tag->framebuffer_common.framebuffer_pitch =
- fb.fb_stride * (bpp / 8);
- tag->framebuffer_common.framebuffer_type =
- MULTIBOOT_FRAMEBUFFER_TYPE_RGB;
- tag->framebuffer_common.mb_reserved = 0;
-
- /*
- * The RGB or BGR color ordering.
- */
- if (fb.fb_mask_red & 0x000000ff) {
- tag->u.fb2.framebuffer_red_field_position = 0;
- tag->u.fb2.framebuffer_blue_field_position = 16;
- } else {
- tag->u.fb2.framebuffer_red_field_position = 16;
- tag->u.fb2.framebuffer_blue_field_position = 0;
- }
- tag->u.fb2.framebuffer_red_mask_size = 8;
- tag->u.fb2.framebuffer_green_field_position = 8;
- tag->u.fb2.framebuffer_green_mask_size = 8;
- tag->u.fb2.framebuffer_blue_mask_size = 8;
+ extern multiboot_tag_framebuffer_t gfx_fb;
+#if defined (EFI)
+
+ tag = (multiboot_tag_framebuffer_t *) mb_malloc(sizeof (*tag));
+ memcpy(tag, &gfx_fb, sizeof (*tag));
+ tag->framebuffer_common.mb_type =
+ MULTIBOOT_TAG_TYPE_FRAMEBUFFER;
+ tag->framebuffer_common.mb_size = sizeof (*tag);
+#else
+ extern multiboot_color_t *cmap;
+ uint32_t size;
+
+ if (gfx_fb.framebuffer_common.framebuffer_type ==
+ MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED) {
+ uint16_t nc;
+ nc = gfx_fb.u.fb1.framebuffer_palette_num_colors;
+ size = sizeof (struct multiboot_tag_framebuffer_common)
+ + sizeof (nc)
+ + nc * sizeof (multiboot_color_t);
+ } else {
+ size = sizeof (gfx_fb);
+ }
+
+ tag = (multiboot_tag_framebuffer_t *) mb_malloc(size);
+ memcpy(tag, &gfx_fb, sizeof (*tag));
+
+ tag->framebuffer_common.mb_type =
+ MULTIBOOT_TAG_TYPE_FRAMEBUFFER;
+ tag->framebuffer_common.mb_size = size;
+
+ if (gfx_fb.framebuffer_common.framebuffer_type ==
+ MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED) {
+ memcpy(tag->u.fb1.framebuffer_palette, cmap,
+ sizeof (multiboot_color_t) *
+ gfx_fb.u.fb1.framebuffer_palette_num_colors);
}
+#endif /* EFI */
}
+#if defined (EFI)
/* Leave EFI memmap last as we will also switch off the BS. */
{
multiboot_tag_efi_mmap_t *tag;
@@ -1173,7 +1209,7 @@ multiboot2_exec(struct preloaded_file *fp)
last_addr += map_size;
last_addr = roundup2(last_addr, MULTIBOOT_TAG_ALIGN);
}
-#endif
+#endif /* EFI */
/*
* MB tag list end marker.
@@ -1251,7 +1287,7 @@ multiboot2_exec(struct preloaded_file *fp)
dev_cleanup();
__exec((void *)VTOP(multiboot_tramp), MULTIBOOT2_BOOTLOADER_MAGIC,
(void *)entry_addr, (void *)VTOP(mbi));
-#endif
+#endif /* EFI */
panic("exec returned");
error:
diff --git a/usr/src/boot/sys/boot/common/tem.c b/usr/src/boot/sys/boot/common/tem.c
new file mode 100644
index 0000000000..8399f835ef
--- /dev/null
+++ b/usr/src/boot/sys/boot/common/tem.c
@@ -0,0 +1,2848 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2016 Joyent, Inc.
+ */
+
+/*
+ * ANSI terminal emulator module; parse ANSI X3.64 escape sequences and
+ * the like.
+ *
+ * How Virtual Terminal Emulator Works:
+ *
+ * Every virtual terminal is associated with a tem_vt_state structure
+ * and maintains a virtual screen buffer in tvs_screen_buf, which contains
+ * all the characters which should be shown on the physical screen when
+ * the terminal is activated.
+ *
+ * Data written to a virtual terminal is composed of characters which
+ * should be displayed on the screen when this virtual terminal is
+ * activated, fg/bg colors of these characters, and other control
+ * information (escape sequence, etc).
+ *
+ * When data is passed to a virtual terminal it first is parsed for
+ * control information by tem_parse(). Subsequently the character
+ * and color data are written to tvs_screen_buf.
+ * They are saved in buffer in order to refresh the screen when this
+ * terminal is activated. If the terminal is currently active, the data
+ * (characters and colors) are also written to the physical screen by
+ * invoking a callback function, tem_text_callbacks() or tem_pix_callbacks().
+ *
+ * When rendering data to the framebuffer, if the framebuffer is in
+ * VIS_PIXEL mode, the character data will first be converted to pixel
+ * data using tem_pix_bit2pix(), and then the pixels get displayed
+ * on the physical screen. We only store the character and color data in
+ * tem_vt_state since the bit2pix conversion only happens when actually
+ * rendering to the physical framebuffer.
+ */
+
+
+#include <stand.h>
+#include <sys/ascii.h>
+#include <sys/errno.h>
+#include <sys/tem_impl.h>
+#ifdef _HAVE_TEM_FIRMWARE
+#include <sys/promif.h>
+#endif /* _HAVE_TEM_FIRMWARE */
+#include <sys/consplat.h>
+#include <sys/kd.h>
+
+extern int lz4_decompress(void *, void *, size_t, size_t, int);
+
+/* Terminal emulator internal helper functions */
+static void tems_setup_terminal(struct vis_devinit *, size_t, size_t);
+static void tems_modechange_callback(struct vis_modechg_arg *,
+ struct vis_devinit *);
+
+static void tems_reset_colormap(void);
+
+static void tem_free_buf(struct tem_vt_state *);
+static void tem_internal_init(struct tem_vt_state *, boolean_t, boolean_t);
+static void tems_get_initial_color(tem_color_t *pcolor);
+
+static void tem_control(struct tem_vt_state *, uint8_t);
+static void tem_setparam(struct tem_vt_state *, int, int);
+static void tem_selgraph(struct tem_vt_state *);
+static void tem_chkparam(struct tem_vt_state *, uint8_t);
+static void tem_getparams(struct tem_vt_state *, uint8_t);
+static void tem_outch(struct tem_vt_state *, tem_char_t);
+static void tem_parse(struct tem_vt_state *, tem_char_t);
+
+static void tem_new_line(struct tem_vt_state *);
+static void tem_cr(struct tem_vt_state *);
+static void tem_lf(struct tem_vt_state *);
+static void tem_send_data(struct tem_vt_state *);
+static void tem_cls(struct tem_vt_state *);
+static void tem_tab(struct tem_vt_state *);
+static void tem_back_tab(struct tem_vt_state *);
+static void tem_clear_tabs(struct tem_vt_state *, int);
+static void tem_set_tab(struct tem_vt_state *);
+static void tem_mv_cursor(struct tem_vt_state *, int, int);
+static void tem_shift(struct tem_vt_state *, int, int);
+static void tem_scroll(struct tem_vt_state *, int, int, int, int);
+static void tem_clear_chars(struct tem_vt_state *tem,
+ int count, screen_pos_t row, screen_pos_t col);
+static void tem_copy_area(struct tem_vt_state *tem,
+ screen_pos_t s_col, screen_pos_t s_row,
+ screen_pos_t e_col, screen_pos_t e_row,
+ screen_pos_t t_col, screen_pos_t t_row);
+static void tem_bell(struct tem_vt_state *tem);
+static void tem_pix_clear_prom_output(struct tem_vt_state *tem);
+
+static void tem_virtual_cls(struct tem_vt_state *, size_t, screen_pos_t,
+ screen_pos_t);
+static void tem_virtual_display(struct tem_vt_state *, term_char_t *,
+ size_t, screen_pos_t, screen_pos_t);
+static void tem_align_cursor(struct tem_vt_state *tem);
+
+static void tem_check_first_time(struct tem_vt_state *tem);
+static void tem_reset_display(struct tem_vt_state *, boolean_t, boolean_t);
+static void tem_terminal_emulate(struct tem_vt_state *, uint8_t *, int);
+static void tem_text_cursor(struct tem_vt_state *, short);
+static void tem_text_cls(struct tem_vt_state *,
+ int count, screen_pos_t row, screen_pos_t col);
+static void tem_pix_display(struct tem_vt_state *, term_char_t *,
+ int, screen_pos_t, screen_pos_t);
+static void tem_pix_copy(struct tem_vt_state *,
+ screen_pos_t, screen_pos_t,
+ screen_pos_t, screen_pos_t,
+ screen_pos_t, screen_pos_t);
+static void tem_pix_cursor(struct tem_vt_state *, short);
+static void tem_get_attr(struct tem_vt_state *, text_color_t *,
+ text_color_t *, text_attr_t *, uint8_t);
+static void tem_get_color(text_color_t *, text_color_t *, term_char_t);
+static void tem_pix_align(struct tem_vt_state *);
+static void tem_text_display(struct tem_vt_state *, term_char_t *, int,
+ screen_pos_t, screen_pos_t);
+static void tem_text_copy(struct tem_vt_state *,
+ screen_pos_t, screen_pos_t, screen_pos_t, screen_pos_t,
+ screen_pos_t, screen_pos_t);
+static void tem_pix_bit2pix(struct tem_vt_state *, term_char_t);
+static void tem_pix_cls_range(struct tem_vt_state *, screen_pos_t, int,
+ int, screen_pos_t, int, int, boolean_t);
+static void tem_pix_cls(struct tem_vt_state *, int,
+ screen_pos_t, screen_pos_t);
+
+static void bit_to_pix4(struct tem_vt_state *tem, tem_char_t c,
+ text_color_t fg_color, text_color_t bg_color);
+static void bit_to_pix8(struct tem_vt_state *tem, tem_char_t c,
+ text_color_t fg_color, text_color_t bg_color);
+static void bit_to_pix16(struct tem_vt_state *tem, tem_char_t c,
+ text_color_t fg_color, text_color_t bg_color);
+static void bit_to_pix24(struct tem_vt_state *tem, tem_char_t c,
+ text_color_t fg_color, text_color_t bg_color);
+static void bit_to_pix32(struct tem_vt_state *tem, tem_char_t c,
+ text_color_t fg_color, text_color_t bg_color);
+
+/*
+ * Globals
+ */
+tem_state_t tems; /* common term info */
+
+tem_callbacks_t tem_text_callbacks = {
+ .tsc_display = &tem_text_display,
+ .tsc_copy = &tem_text_copy,
+ .tsc_cursor = &tem_text_cursor,
+ .tsc_bit2pix = NULL,
+ .tsc_cls = &tem_text_cls
+};
+tem_callbacks_t tem_pix_callbacks = {
+ .tsc_display = &tem_pix_display,
+ .tsc_copy = &tem_pix_copy,
+ .tsc_cursor = &tem_pix_cursor,
+ .tsc_bit2pix = &tem_pix_bit2pix,
+ .tsc_cls = &tem_pix_cls
+};
+
+#define tem_callback_display (*tems.ts_callbacks->tsc_display)
+#define tem_callback_copy (*tems.ts_callbacks->tsc_copy)
+#define tem_callback_cursor (*tems.ts_callbacks->tsc_cursor)
+#define tem_callback_cls (*tems.ts_callbacks->tsc_cls)
+#define tem_callback_bit2pix (*tems.ts_callbacks->tsc_bit2pix)
+
+static void
+tem_add(struct tem_vt_state *tem)
+{
+ list_insert_head(&tems.ts_list, tem);
+}
+
+/*
+ * This is the main entry point to the module. It handles output requests
+ * during normal system operation, when (e.g.) mutexes are available.
+ */
+void
+tem_write(tem_vt_state_t tem_arg, uint8_t *buf, ssize_t len)
+{
+ struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg;
+
+ if (!tem->tvs_initialized) {
+ return;
+ }
+
+ tem_check_first_time(tem);
+ tem_terminal_emulate(tem, buf, len);
+}
+
+static void
+tem_internal_init(struct tem_vt_state *ptem,
+ boolean_t init_color, boolean_t clear_screen)
+{
+ size_t size, width, height;
+
+ if (tems.ts_display_mode == VIS_PIXEL) {
+ ptem->tvs_pix_data_size = tems.ts_pix_data_size;
+ ptem->tvs_pix_data = malloc(ptem->tvs_pix_data_size);
+ }
+
+ width = tems.ts_c_dimension.width;
+ height = tems.ts_c_dimension.height;
+
+ size = width * sizeof (tem_char_t);
+ ptem->tvs_outbuf = malloc(size);
+ if (ptem->tvs_outbuf == NULL)
+ panic("out of memory in tem_internal_init()\n");
+
+ tem_reset_display(ptem, clear_screen, init_color);
+
+ ptem->tvs_utf8_left = 0;
+ ptem->tvs_utf8_partial = 0;
+
+ ptem->tvs_initialized = true;
+
+ /*
+ * Out of memory is not fatal there, without the screen history,
+ * we can not optimize the screen copy.
+ */
+ size = width * height * sizeof (term_char_t);
+ ptem->tvs_screen_buf = malloc(size);
+ tem_virtual_cls(ptem, width * height, 0, 0);
+}
+
+int
+tem_initialized(tem_vt_state_t tem_arg)
+{
+ struct tem_vt_state *ptem = (struct tem_vt_state *)tem_arg;
+
+ return (ptem->tvs_initialized);
+}
+
+tem_vt_state_t
+tem_init(void)
+{
+ struct tem_vt_state *ptem;
+
+ ptem = malloc(sizeof (struct tem_vt_state));
+ if (ptem == NULL)
+ return ((tem_vt_state_t)ptem);
+ bzero(ptem, sizeof (*ptem));
+
+ ptem->tvs_isactive = false;
+ ptem->tvs_fbmode = KD_TEXT;
+
+ /*
+ * A tem is regarded as initialized only after tem_internal_init(),
+ * will be set at the end of tem_internal_init().
+ */
+ ptem->tvs_initialized = 0;
+
+ if (!tems.ts_initialized) {
+ /*
+ * Only happens during early console configuration.
+ */
+ tem_add(ptem);
+ return ((tem_vt_state_t)ptem);
+ }
+
+ tem_internal_init(ptem, B_TRUE, B_FALSE);
+ tem_add(ptem);
+
+ return ((tem_vt_state_t)ptem);
+}
+
+/*
+ * re-init the tem after video mode has changed and tems_info has
+ * been re-inited.
+ */
+static void
+tem_reinit(struct tem_vt_state *tem, boolean_t reset_display)
+{
+ tem_free_buf(tem); /* only free virtual buffers */
+
+ /* reserve color */
+ tem_internal_init(tem, B_FALSE, reset_display);
+}
+
+static void
+tem_free_buf(struct tem_vt_state *tem)
+{
+ free(tem->tvs_outbuf);
+ tem->tvs_outbuf = NULL;
+
+ free(tem->tvs_pix_data);
+ tem->tvs_pix_data = NULL;
+
+ free(tem->tvs_screen_buf);
+ tem->tvs_screen_buf = NULL;
+}
+
+static int
+tems_failed(boolean_t finish_ioctl)
+{
+ if (finish_ioctl && tems.ts_hdl != NULL)
+ (void) tems.ts_hdl->c_ioctl(tems.ts_hdl, VIS_DEVFINI, NULL);
+
+ tems.ts_hdl = NULL;
+ return (ENXIO);
+}
+
+/*
+ * Only called once during boot
+ */
+int
+tem_info_init(struct console *cp)
+{
+ int ret;
+ struct vis_devinit temargs;
+ size_t height = 0;
+ size_t width = 0;
+ struct tem_vt_state *p;
+
+ if (tems.ts_initialized) {
+ return (0);
+ }
+
+ list_create(&tems.ts_list, sizeof (struct tem_vt_state),
+ __offsetof(struct tem_vt_state, tvs_list_node));
+ tems.ts_active = NULL;
+
+ tems.ts_hdl = cp;
+ bzero(&temargs, sizeof (temargs));
+ temargs.modechg_cb = (vis_modechg_cb_t)tems_modechange_callback;
+ temargs.modechg_arg = NULL;
+
+ /*
+ * Initialize the console and get the device parameters
+ */
+ if (cp->c_ioctl(cp, VIS_DEVINIT, &temargs) != 0) {
+ printf("terminal emulator: Compatible fb not found\n");
+ ret = tems_failed(B_FALSE);
+ return (ret);
+ }
+
+ /* Make sure the fb driver and terminal emulator versions match */
+ if (temargs.version != VIS_CONS_REV) {
+ printf(
+ "terminal emulator: VIS_CONS_REV %d (see sys/visual_io.h) "
+ "of console fb driver not supported\n", temargs.version);
+ ret = tems_failed(B_TRUE);
+ return (ret);
+ }
+
+ /* other sanity checks */
+ if (!((temargs.depth == 4) || (temargs.depth == 8) ||
+ (temargs.depth == 15) || (temargs.depth == 16) ||
+ (temargs.depth == 24) || (temargs.depth == 32))) {
+ printf("terminal emulator: unsupported depth\n");
+ ret = tems_failed(B_TRUE);
+ return (ret);
+ }
+
+ if ((temargs.mode != VIS_TEXT) && (temargs.mode != VIS_PIXEL)) {
+ printf("terminal emulator: unsupported mode\n");
+ ret = tems_failed(B_TRUE);
+ return (ret);
+ }
+
+ plat_tem_get_prom_size(&height, &width);
+
+ /*
+ * Initialize the common terminal emulator info
+ */
+ tems_setup_terminal(&temargs, height, width);
+
+ tems_reset_colormap();
+ tems_get_initial_color(&tems.ts_init_color);
+
+ tems.ts_initialized = 1; /* initialization flag */
+
+ for (p = list_head(&tems.ts_list); p != NULL;
+ p = list_next(&tems.ts_list, p)) {
+ tem_internal_init(p, B_TRUE, B_FALSE);
+ if (temargs.mode == VIS_PIXEL)
+ tem_pix_align(p);
+ }
+
+ return (0);
+}
+
+#define TEMS_DEPTH_DIFF 0x01
+#define TEMS_DIMENSION_DIFF 0x02
+
+static uint8_t
+tems_check_videomode(struct vis_devinit *tp)
+{
+ uint8_t result = 0;
+
+ if (tems.ts_pdepth != tp->depth)
+ result |= TEMS_DEPTH_DIFF;
+
+ if (tp->mode == VIS_TEXT) {
+ if (tems.ts_c_dimension.width != tp->width ||
+ tems.ts_c_dimension.height != tp->height)
+ result |= TEMS_DIMENSION_DIFF;
+ } else {
+ if (tems.ts_p_dimension.width != tp->width ||
+ tems.ts_p_dimension.height != tp->height)
+ result |= TEMS_DIMENSION_DIFF;
+ }
+ if (tems.update_font == true)
+ result |= TEMS_DIMENSION_DIFF;
+
+ return (result);
+}
+
+static int
+env_screen_nounset(struct env_var *ev __unused)
+{
+ if (tems.ts_p_dimension.width == 0 &&
+ tems.ts_p_dimension.height == 0)
+ return (0);
+ return(EPERM);
+}
+
+static void
+tems_setup_terminal(struct vis_devinit *tp, size_t height, size_t width)
+{
+ bitmap_data_t *font_data;
+ int i;
+ char env[8];
+
+ tems.ts_pdepth = tp->depth;
+ tems.ts_linebytes = tp->linebytes;
+ tems.ts_display_mode = tp->mode;
+ tems.ts_color_map = tp->color_map;
+
+ switch (tp->mode) {
+ case VIS_TEXT:
+ tems.ts_p_dimension.width = 0;
+ tems.ts_p_dimension.height = 0;
+ tems.ts_c_dimension.width = tp->width;
+ tems.ts_c_dimension.height = tp->height;
+ tems.ts_callbacks = &tem_text_callbacks;
+
+ snprintf(env, sizeof (env), "%d", tems.ts_c_dimension.height);
+ env_setenv("screen-#rows", EV_VOLATILE | EV_NOHOOK, env,
+ env_noset, env_nounset);
+ snprintf(env, sizeof (env), "%d", tems.ts_c_dimension.width);
+ env_setenv("screen-#cols", EV_VOLATILE | EV_NOHOOK, env,
+ env_noset, env_nounset);
+
+ /* ensure the following are not set for text mode */
+ unsetenv("screen-height");
+ unsetenv("screen-width");
+ break;
+
+ case VIS_PIXEL:
+ /*
+ * First check to see if the user has specified a screen size.
+ * If so, use those values. Else use 34x80 as the default.
+ */
+ if (width == 0) {
+ width = TEM_DEFAULT_COLS;
+ height = TEM_DEFAULT_ROWS;
+ }
+ tems.ts_c_dimension.height = (screen_size_t)height;
+ tems.ts_c_dimension.width = (screen_size_t)width;
+
+ tems.ts_p_dimension.height = tp->height;
+ tems.ts_p_dimension.width = tp->width;
+
+ tems.ts_callbacks = &tem_pix_callbacks;
+
+ /*
+ * set_font() will select a appropriate sized font for
+ * the number of rows and columns selected. If we don't
+ * have a font that will fit, then it will use the
+ * default builtin font and adjust the rows and columns
+ * to fit on the screen.
+ */
+ font_data = set_font(&tems.ts_c_dimension.height,
+ &tems.ts_c_dimension.width,
+ tems.ts_p_dimension.height,
+ tems.ts_p_dimension.width);
+
+ /*
+ * The built in font is compressed, to use it, we
+ * uncompress it into the allocated buffer.
+ * To use loaded font, we assign the loaded buffer.
+ * In case of next load, the previously loaded data
+ * is freed by the process of loading the new font.
+ */
+ tems.update_font = false;
+
+ if (tems.ts_font.vf_bytes == NULL) {
+ for (i = 0; i < VFNT_MAPS; i++) {
+ tems.ts_font.vf_map[i] =
+ font_data->font->vf_map[i];
+ }
+
+ if (font_data->compressed_size != 0) {
+ /*
+ * We only expect this allocation to
+ * happen at startup, and therefore not to fail.
+ */
+ tems.ts_font.vf_bytes =
+ malloc(font_data->uncompressed_size);
+ if (tems.ts_font.vf_bytes == NULL)
+ panic("out of memory\n");
+ (void)lz4_decompress(font_data->compressed_data,
+ tems.ts_font.vf_bytes,
+ font_data->compressed_size,
+ font_data->uncompressed_size, 0);
+ } else {
+ tems.ts_font.vf_bytes =
+ font_data->font->vf_bytes;
+ }
+ tems.ts_font.vf_width = font_data->font->vf_width;
+ tems.ts_font.vf_height = font_data->font->vf_height;
+ for (i = 0; i < VFNT_MAPS; i++) {
+ tems.ts_font.vf_map_count[i] =
+ font_data->font->vf_map_count[i];
+ }
+ }
+
+ snprintf(env, sizeof (env), "%d", tems.ts_c_dimension.height);
+ env_setenv("screen-#rows", EV_VOLATILE | EV_NOHOOK, env,
+ env_noset, env_nounset);
+ snprintf(env, sizeof (env), "%d", tems.ts_c_dimension.width);
+ env_setenv("screen-#cols", EV_VOLATILE | EV_NOHOOK, env,
+ env_noset, env_nounset);
+
+ snprintf(env, sizeof (env), "%d", tems.ts_p_dimension.height);
+ env_setenv("screen-height", EV_VOLATILE | EV_NOHOOK, env,
+ env_noset, env_screen_nounset);
+ snprintf(env, sizeof (env), "%d", tems.ts_p_dimension.width);
+ env_setenv("screen-width", EV_VOLATILE | EV_NOHOOK, env,
+ env_noset, env_screen_nounset);
+
+ snprintf(env, sizeof (env), "%dx%d", tems.ts_font.vf_width,
+ tems.ts_font.vf_height);
+ env_setenv("screen-font", EV_VOLATILE | EV_NOHOOK, env, NULL,
+ NULL);
+
+ tems.ts_p_offset.y = (tems.ts_p_dimension.height -
+ (tems.ts_c_dimension.height * tems.ts_font.vf_height)) / 2;
+ tems.ts_p_offset.x = (tems.ts_p_dimension.width -
+ (tems.ts_c_dimension.width * tems.ts_font.vf_width)) / 2;
+
+ tems.ts_pix_data_size =
+ tems.ts_font.vf_width * tems.ts_font.vf_height;
+
+ tems.ts_pix_data_size *= 4;
+
+ tems.ts_pdepth = tp->depth;
+
+ break;
+ }
+}
+
+/*
+ * This is a callback function that we register with the frame
+ * buffer driver layered underneath. It gets invoked from
+ * the underlying frame buffer driver to reconfigure the terminal
+ * emulator to a new screen size and depth in conjunction with
+ * framebuffer videomode changes.
+ * Here we keep the foreground/background color and attributes,
+ * which may be different with the initial settings, so that
+ * the color won't change while the framebuffer videomode changes.
+ * And we also reset the kernel terminal emulator and clear the
+ * whole screen.
+ */
+/* ARGSUSED */
+void
+tems_modechange_callback(struct vis_modechg_arg *arg __unused,
+ struct vis_devinit *devinit)
+{
+ uint8_t diff;
+ struct tem_vt_state *p;
+ tem_modechg_cb_t cb;
+ tem_modechg_cb_arg_t cb_arg;
+ size_t height = 0;
+ size_t width = 0;
+
+ diff = tems_check_videomode(devinit);
+ if (diff == 0) {
+ /*
+ * This is color related change, reset color and redraw the
+ * screen. Only need to reinit the active tem.
+ */
+ struct tem_vt_state *active = tems.ts_active;
+ tems_get_initial_color(&tems.ts_init_color);
+ active->tvs_fg_color = tems.ts_init_color.fg_color;
+ active->tvs_bg_color = tems.ts_init_color.bg_color;
+ active->tvs_flags = tems.ts_init_color.a_flags;
+ tem_reinit(active, B_TRUE);
+ return;
+ }
+
+ diff = diff & TEMS_DIMENSION_DIFF;
+
+ if (diff == 0) {
+ /*
+ * Only need to reinit the active tem.
+ */
+ struct tem_vt_state *active = tems.ts_active;
+ tems.ts_pdepth = devinit->depth;
+ /* color depth did change, reset colors */
+ tems_reset_colormap();
+ tems_get_initial_color(&tems.ts_init_color);
+ tem_reinit(active, B_TRUE);
+
+ return;
+ }
+
+ plat_tem_get_prom_size(&height, &width);
+
+ tems_setup_terminal(devinit, height, width);
+
+ tems_reset_colormap();
+ tems_get_initial_color(&tems.ts_init_color);
+
+ for (p = list_head(&tems.ts_list); p != NULL;
+ p = list_next(&tems.ts_list, p)) {
+ tem_reinit(p, p->tvs_isactive);
+ }
+
+
+ if (tems.ts_modechg_cb == NULL) {
+ return;
+ }
+
+ cb = tems.ts_modechg_cb;
+ cb_arg = tems.ts_modechg_arg;
+
+ cb(cb_arg);
+}
+
+/*
+ * This function is used to clear entire screen via the underlying framebuffer
+ * driver.
+ */
+int
+tems_cls(struct vis_consclear *pda)
+{
+ if (tems.ts_hdl == NULL)
+ return (1);
+ return (tems.ts_hdl->c_ioctl(tems.ts_hdl, VIS_CONSCLEAR, pda));
+}
+
+/*
+ * This function is used to display a rectangular blit of data
+ * of a given size and location via the underlying framebuffer driver.
+ * The blit can be as small as a pixel or as large as the screen.
+ */
+void
+tems_display(struct vis_consdisplay *pda)
+{
+ if (tems.ts_hdl != NULL)
+ (void) tems.ts_hdl->c_ioctl(tems.ts_hdl, VIS_CONSDISPLAY, pda);
+}
+
+/*
+ * This function is used to invoke a block copy operation in the
+ * underlying framebuffer driver. Rectangle copies are how scrolling
+ * is implemented, as well as horizontal text shifting escape seqs.
+ * such as from vi when deleting characters and words.
+ */
+void
+tems_copy(struct vis_conscopy *pma)
+{
+ if (tems.ts_hdl != NULL)
+ (void) tems.ts_hdl->c_ioctl(tems.ts_hdl, VIS_CONSCOPY, pma);
+}
+
+/*
+ * This function is used to show or hide a rectangluar monochrom
+ * pixel inverting, text block cursor via the underlying framebuffer.
+ */
+void
+tems_cursor(struct vis_conscursor *pca)
+{
+ if (tems.ts_hdl != NULL)
+ (void) tems.ts_hdl->c_ioctl(tems.ts_hdl, VIS_CONSCURSOR, pca);
+}
+
+static void
+tem_kdsetmode(int mode)
+{
+ if (tems.ts_hdl != NULL)
+ (void) tems.ts_hdl->c_ioctl(tems.ts_hdl, KDSETMODE,
+ (void *)(intptr_t)mode);
+}
+
+static void
+tems_reset_colormap(void)
+{
+ struct vis_cmap cm;
+
+ switch (tems.ts_pdepth) {
+ case 8:
+ cm.index = 0;
+ cm.count = 16;
+ /* 8-bits (1/3 of TrueColor 24) */
+ cm.red = (uint8_t *)cmap4_to_24.red;
+ /* 8-bits (1/3 of TrueColor 24) */
+ cm.blue = (uint8_t *)cmap4_to_24.blue;
+ /* 8-bits (1/3 of TrueColor 24) */
+ cm.green = (uint8_t *)cmap4_to_24.green;
+ if (tems.ts_hdl != NULL)
+ (void) tems.ts_hdl->c_ioctl(tems.ts_hdl,
+ VIS_PUTCMAP, &cm);
+ break;
+ }
+}
+
+void
+tem_get_size(uint16_t *r, uint16_t *c, uint16_t *x, uint16_t *y)
+{
+ *r = (uint16_t)tems.ts_c_dimension.height;
+ *c = (uint16_t)tems.ts_c_dimension.width;
+ *x = (uint16_t)tems.ts_p_dimension.width;
+ *y = (uint16_t)tems.ts_p_dimension.height;
+}
+
+/*
+ * Loader extension. Store important data in environment. Intended to be used
+ * just before booting the OS to make the data available in kernel
+ * environment module.
+ */
+void
+tem_save_state(void)
+{
+ struct tem_vt_state *active = tems.ts_active;
+ char buf[80];
+
+ /*
+ * We already have in environment:
+ * tem.inverse, tem.inverse_screen
+ * tem.fg_color, tem.bg_color.
+ * So we only need to add the position of the cursor.
+ */
+
+ if (active != NULL) {
+ snprintf(buf, sizeof (buf), "%d", active->tvs_c_cursor.col);
+ setenv("tem.cursor.col", buf, 1);
+ snprintf(buf, sizeof (buf), "%d", active->tvs_c_cursor.row);
+ setenv("tem.cursor.row", buf, 1);
+ }
+}
+
+void
+tem_register_modechg_cb(tem_modechg_cb_t func, tem_modechg_cb_arg_t arg)
+{
+ tems.ts_modechg_cb = func;
+ tems.ts_modechg_arg = arg;
+}
+
+/*
+ * This function is to scroll up the OBP output, which has
+ * different screen height and width with our kernel console.
+ */
+static void
+tem_prom_scroll_up(struct tem_vt_state *tem, int nrows)
+{
+ struct vis_conscopy ma;
+ int ncols, width;
+
+ /* copy */
+ ma.s_row = nrows * tems.ts_font.vf_height;
+ ma.e_row = tems.ts_p_dimension.height - 1;
+ ma.t_row = 0;
+
+ ma.s_col = 0;
+ ma.e_col = tems.ts_p_dimension.width - 1;
+ ma.t_col = 0;
+
+ tems_copy(&ma);
+
+ /* clear */
+ width = tems.ts_font.vf_width;
+ ncols = (tems.ts_p_dimension.width + (width - 1))/ width;
+
+ tem_pix_cls_range(tem, 0, nrows, tems.ts_p_offset.y,
+ 0, ncols, 0, B_TRUE);
+}
+
+/*
+ * This function is to compute the starting row of the console, according to
+ * PROM cursor's position. Here we have to take different fonts into account.
+ */
+static int
+tem_adjust_row(struct tem_vt_state *tem, int prom_row)
+{
+ int tem_row;
+ int tem_y;
+ int prom_charheight = 0;
+ int prom_window_top = 0;
+ int scroll_up_lines;
+
+ plat_tem_get_prom_font_size(&prom_charheight, &prom_window_top);
+ if (prom_charheight == 0)
+ prom_charheight = tems.ts_font.vf_height;
+
+ tem_y = (prom_row + 1) * prom_charheight + prom_window_top -
+ tems.ts_p_offset.y;
+ tem_row = (tem_y + tems.ts_font.vf_height - 1) /
+ tems.ts_font.vf_height - 1;
+
+ if (tem_row < 0) {
+ tem_row = 0;
+ } else if (tem_row >= (tems.ts_c_dimension.height - 1)) {
+ /*
+ * Scroll up the prom outputs if the PROM cursor's position is
+ * below our tem's lower boundary.
+ */
+ scroll_up_lines = tem_row -
+ (tems.ts_c_dimension.height - 1);
+ tem_prom_scroll_up(tem, scroll_up_lines);
+ tem_row = tems.ts_c_dimension.height - 1;
+ }
+
+ return (tem_row);
+}
+
+static void
+tem_pix_align(struct tem_vt_state *tem)
+{
+ uint32_t row = 0;
+ uint32_t col = 0;
+
+ if (plat_stdout_is_framebuffer()) {
+ plat_tem_hide_prom_cursor();
+
+ /*
+ * We are getting the current cursor position in pixel
+ * mode so that we don't over-write the console output
+ * during boot.
+ */
+ plat_tem_get_prom_pos(&row, &col);
+
+ /*
+ * Adjust the row if necessary when the font of our
+ * kernel console tem is different with that of prom
+ * tem.
+ */
+ row = tem_adjust_row(tem, row);
+
+ /* first line of our kernel console output */
+ tem->tvs_first_line = row + 1;
+
+ /* re-set and align cursor position */
+ tem->tvs_s_cursor.row = tem->tvs_c_cursor.row =
+ (screen_pos_t)row;
+ tem->tvs_s_cursor.col = tem->tvs_c_cursor.col = 0;
+ } else {
+ tem_reset_display(tem, B_TRUE, B_TRUE);
+ }
+}
+
+static void
+tems_get_inverses(boolean_t *p_inverse, boolean_t *p_inverse_screen)
+{
+ int i_inverse = 0;
+ int i_inverse_screen = 0;
+
+ plat_tem_get_inverses(&i_inverse, &i_inverse_screen);
+
+ *p_inverse = (i_inverse == 0) ? B_FALSE : B_TRUE;
+ *p_inverse_screen = (i_inverse_screen == 0) ? B_FALSE : B_TRUE;
+}
+
+/*
+ * Get the foreground/background color and attributes from environment.
+ */
+static void
+tems_get_initial_color(tem_color_t *pcolor)
+{
+ boolean_t inverse, inverse_screen;
+ unsigned short flags = 0;
+
+ pcolor->fg_color = DEFAULT_ANSI_FOREGROUND;
+ pcolor->bg_color = DEFAULT_ANSI_BACKGROUND;
+ plat_tem_get_colors(&pcolor->fg_color, &pcolor->bg_color);
+
+ tems_get_inverses(&inverse, &inverse_screen);
+ if (inverse)
+ flags |= TEM_ATTR_REVERSE;
+ if (inverse_screen)
+ flags |= TEM_ATTR_SCREEN_REVERSE;
+
+ /*
+ * In case of black on white we want bright white for BG.
+ * In case if white on black, to improve readability,
+ * we want bold white.
+ */
+ if (flags != 0) {
+ /*
+ * If either reverse flag is set, the screen is in
+ * white-on-black mode. We set the bold flag to
+ * improve readability.
+ */
+ flags |= TEM_ATTR_BOLD;
+ } else {
+ /*
+ * Otherwise, the screen is in black-on-white mode.
+ * The SPARC PROM console, which starts in this mode,
+ * uses the bright white background colour so we
+ * match it here.
+ */
+ if (pcolor->bg_color == ANSI_COLOR_WHITE)
+ flags |= TEM_ATTR_BRIGHT_BG;
+ }
+
+ pcolor->a_flags = flags;
+}
+
+void
+tem_activate(tem_vt_state_t tem_arg, boolean_t unblank)
+{
+ struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg;
+
+ tems.ts_active = tem;
+ tem->tvs_isactive = true;
+
+ tem_kdsetmode(tem->tvs_fbmode);
+
+ if (unblank)
+ tem_cls(tem);
+}
+
+static void
+tem_check_first_time(struct tem_vt_state *tem)
+{
+ static int first_time = 1;
+
+ /*
+ * Realign the console cursor. We did this in tem_init().
+ * However, drivers in the console stream may emit additional
+ * messages before we are ready. This causes text overwrite
+ * on the screen. This is a workaround.
+ */
+ if (!first_time)
+ return;
+
+ first_time = 0;
+ if (tems.ts_display_mode == VIS_TEXT)
+ tem_text_cursor(tem, VIS_GET_CURSOR);
+ else
+ tem_pix_cursor(tem, VIS_GET_CURSOR);
+ tem_align_cursor(tem);
+}
+
+/* Process partial UTF-8 sequence. */
+static void
+tem_input_partial(struct tem_vt_state *tem)
+{
+ unsigned i;
+ tem_char_t c;
+
+ if (tem->tvs_utf8_left == 0)
+ return;
+
+ for (i = 0; i < sizeof (tem->tvs_utf8_partial); i++) {
+ c = (tem->tvs_utf8_partial >> (24 - (i << 3))) & 0xff;
+ if (c != 0) {
+ tem_parse(tem, c);
+ }
+ }
+ tem->tvs_utf8_left = 0;
+ tem->tvs_utf8_partial = 0;
+}
+
+/*
+ * Handle UTF-8 sequences.
+ */
+static void
+tem_input_byte(struct tem_vt_state *tem, uint8_t c)
+{
+ /*
+ * Check for UTF-8 code points. In case of error fall back to
+ * 8-bit code. As we only have 8859-1 fonts for console, this will set
+ * the limits on what chars we actually can display, therefore we
+ * have to return to this code once we have solved the font issue.
+ */
+ if ((c & 0x80) == 0x00) {
+ /* One-byte sequence. */
+ tem_input_partial(tem);
+ tem_parse(tem, c);
+ return;
+ }
+ if ((c & 0xe0) == 0xc0) {
+ /* Two-byte sequence. */
+ tem_input_partial(tem);
+ tem->tvs_utf8_left = 1;
+ tem->tvs_utf8_partial = c;
+ return;
+ }
+ if ((c & 0xf0) == 0xe0) {
+ /* Three-byte sequence. */
+ tem_input_partial(tem);
+ tem->tvs_utf8_left = 2;
+ tem->tvs_utf8_partial = c;
+ return;
+ }
+ if ((c & 0xf8) == 0xf0) {
+ /* Four-byte sequence. */
+ tem_input_partial(tem);
+ tem->tvs_utf8_left = 3;
+ tem->tvs_utf8_partial = c;
+ return;
+ }
+ if ((c & 0xc0) == 0x80) {
+ /* Invalid state? */
+ if (tem->tvs_utf8_left == 0) {
+ tem_parse(tem, c);
+ return;
+ }
+ tem->tvs_utf8_left--;
+ tem->tvs_utf8_partial = (tem->tvs_utf8_partial << 8) | c;
+ if (tem->tvs_utf8_left == 0) {
+ tem_char_t v, u;
+ uint8_t b;
+
+ /*
+ * Transform the sequence of 2 to 4 bytes to
+ * unicode number.
+ */
+ v = 0;
+ u = tem->tvs_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);
+ }
+
+ tem_parse(tem, v);
+ tem->tvs_utf8_partial = 0;
+ }
+ return;
+ }
+ /* Anything left is illegal in UTF-8 sequence. */
+ tem_input_partial(tem);
+ tem_parse(tem, c);
+}
+
+/*
+ * This is the main entry point into the terminal emulator.
+ *
+ * For each data message coming downstream, ANSI assumes that it is composed
+ * of ASCII characters, which are treated as a byte-stream input to the
+ * parsing state machine. All data is parsed immediately -- there is
+ * no enqueing.
+ */
+static void
+tem_terminal_emulate(struct tem_vt_state *tem, uint8_t *buf, int len)
+{
+ if (tem->tvs_isactive)
+ tem_callback_cursor(tem, VIS_HIDE_CURSOR);
+
+ for (; len > 0; len--, buf++)
+ tem_input_byte(tem, *buf);
+
+ /*
+ * Send the data we just got to the framebuffer.
+ */
+ tem_send_data(tem);
+
+ if (tem->tvs_isactive)
+ tem_callback_cursor(tem, VIS_DISPLAY_CURSOR);
+}
+
+/*
+ * send the appropriate control message or set state based on the
+ * value of the control character ch
+ */
+
+static void
+tem_control(struct tem_vt_state *tem, uint8_t ch)
+{
+ tem->tvs_state = A_STATE_START;
+ switch (ch) {
+ case A_BEL:
+ tem_bell(tem);
+ break;
+
+ case A_BS:
+ tem_mv_cursor(tem,
+ tem->tvs_c_cursor.row,
+ tem->tvs_c_cursor.col - 1);
+ break;
+
+ case A_HT:
+ tem_tab(tem);
+ break;
+
+ case A_NL:
+ /*
+ * tem_send_data(tem, credp, called_from);
+ * tem_new_line(tem, credp, called_from);
+ * break;
+ */
+
+ case A_VT:
+ tem_send_data(tem);
+ tem_lf(tem);
+ break;
+
+ case A_FF:
+ tem_send_data(tem);
+ tem_cls(tem);
+ break;
+
+ case A_CR:
+ tem_send_data(tem);
+ tem_cr(tem);
+ break;
+
+ case A_ESC:
+ tem->tvs_state = A_STATE_ESC;
+ break;
+
+ case A_CSI:
+ {
+ int i;
+ tem->tvs_curparam = 0;
+ tem->tvs_paramval = 0;
+ tem->tvs_gotparam = B_FALSE;
+ /* clear the parameters */
+ for (i = 0; i < TEM_MAXPARAMS; i++)
+ tem->tvs_params[i] = -1;
+ tem->tvs_state = A_STATE_CSI;
+ }
+ break;
+
+ case A_GS:
+ tem_back_tab(tem);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/*
+ * if parameters [0..count - 1] are not set, set them to the value
+ * of newparam.
+ */
+
+static void
+tem_setparam(struct tem_vt_state *tem, int count, int newparam)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ if (tem->tvs_params[i] == -1)
+ tem->tvs_params[i] = newparam;
+ }
+}
+
+
+/*
+ * select graphics mode based on the param vals stored in a_params
+ */
+static void
+tem_selgraph(struct tem_vt_state *tem)
+{
+ int curparam;
+ int count = 0;
+ int param;
+
+ tem->tvs_state = A_STATE_START;
+
+ curparam = tem->tvs_curparam;
+ do {
+ param = tem->tvs_params[count];
+
+ switch (param) {
+ case -1:
+ case 0:
+ /* reset to initial normal settings */
+ tem->tvs_fg_color = tems.ts_init_color.fg_color;
+ tem->tvs_bg_color = tems.ts_init_color.bg_color;
+ tem->tvs_flags = tems.ts_init_color.a_flags;
+ break;
+
+ case 1: /* Bold Intense */
+ tem->tvs_flags |= TEM_ATTR_BOLD;
+ break;
+
+ case 2: /* Faint Intense */
+ tem->tvs_flags &= ~TEM_ATTR_BOLD;
+ break;
+
+ case 4: /* Underline */
+ tem->tvs_flags |= TEM_ATTR_UNDERLINE;
+ break;
+
+ case 5: /* Blink */
+ tem->tvs_flags |= TEM_ATTR_BLINK;
+ break;
+
+ case 7: /* Reverse video */
+ if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) {
+ tem->tvs_flags &= ~TEM_ATTR_REVERSE;
+ } else {
+ tem->tvs_flags |= TEM_ATTR_REVERSE;
+ }
+ break;
+
+ case 22: /* Remove Bold */
+ tem->tvs_flags &= ~TEM_ATTR_BOLD;
+ break;
+
+ case 24: /* Remove Underline */
+ tem->tvs_flags &= ~TEM_ATTR_UNDERLINE;
+ break;
+
+ case 25: /* Remove Blink */
+ tem->tvs_flags &= ~TEM_ATTR_BLINK;
+ break;
+
+ case 27: /* Remove Reverse */
+ if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) {
+ tem->tvs_flags |= TEM_ATTR_REVERSE;
+ } else {
+ tem->tvs_flags &= ~TEM_ATTR_REVERSE;
+ }
+ break;
+
+ case 30: /* black (grey) foreground */
+ case 31: /* red (light red) foreground */
+ case 32: /* green (light green) foreground */
+ case 33: /* brown (yellow) foreground */
+ case 34: /* blue (light blue) foreground */
+ case 35: /* magenta (light magenta) foreground */
+ case 36: /* cyan (light cyan) foreground */
+ case 37: /* white (bright white) foreground */
+ tem->tvs_fg_color = param - 30;
+ tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG;
+ break;
+
+ case 39:
+ /*
+ * Reset the foreground colour and brightness.
+ */
+ tem->tvs_fg_color = tems.ts_init_color.fg_color;
+ if (tems.ts_init_color.a_flags & TEM_ATTR_BRIGHT_FG)
+ tem->tvs_flags |= TEM_ATTR_BRIGHT_FG;
+ else
+ tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG;
+ break;
+
+ case 40: /* black (grey) background */
+ case 41: /* red (light red) background */
+ case 42: /* green (light green) background */
+ case 43: /* brown (yellow) background */
+ case 44: /* blue (light blue) background */
+ case 45: /* magenta (light magenta) background */
+ case 46: /* cyan (light cyan) background */
+ case 47: /* white (bright white) background */
+ tem->tvs_bg_color = param - 40;
+ tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG;
+ break;
+
+ case 49:
+ /*
+ * Reset the background colour and brightness.
+ */
+ tem->tvs_bg_color = tems.ts_init_color.bg_color;
+ if (tems.ts_init_color.a_flags & TEM_ATTR_BRIGHT_BG)
+ tem->tvs_flags |= TEM_ATTR_BRIGHT_BG;
+ else
+ tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG;
+ break;
+
+ case 90: /* black (grey) foreground */
+ case 91: /* red (light red) foreground */
+ case 92: /* green (light green) foreground */
+ case 93: /* brown (yellow) foreground */
+ case 94: /* blue (light blue) foreground */
+ case 95: /* magenta (light magenta) foreground */
+ case 96: /* cyan (light cyan) foreground */
+ case 97: /* white (bright white) foreground */
+ tem->tvs_fg_color = param - 90;
+ tem->tvs_flags |= TEM_ATTR_BRIGHT_FG;
+ break;
+
+ case 100: /* black (grey) background */
+ case 101: /* red (light red) background */
+ case 102: /* green (light green) background */
+ case 103: /* brown (yellow) background */
+ case 104: /* blue (light blue) background */
+ case 105: /* magenta (light magenta) background */
+ case 106: /* cyan (light cyan) background */
+ case 107: /* white (bright white) background */
+ tem->tvs_bg_color = param - 100;
+ tem->tvs_flags |= TEM_ATTR_BRIGHT_BG;
+ break;
+
+ default:
+ break;
+ }
+ count++;
+ curparam--;
+
+ } while (curparam > 0);
+}
+
+/*
+ * perform the appropriate action for the escape sequence
+ *
+ * General rule: This code does not validate the arguments passed.
+ * It assumes that the next lower level will do so.
+ */
+static void
+tem_chkparam(struct tem_vt_state *tem, uint8_t ch)
+{
+ int i;
+ int row;
+ int col;
+
+ row = tem->tvs_c_cursor.row;
+ col = tem->tvs_c_cursor.col;
+
+ switch (ch) {
+
+ case 'm': /* select terminal graphics mode */
+ tem_send_data(tem);
+ tem_selgraph(tem);
+ break;
+
+ case '@': /* insert char */
+ tem_setparam(tem, 1, 1);
+ tem_shift(tem, tem->tvs_params[0], TEM_SHIFT_RIGHT);
+ break;
+
+ case 'A': /* cursor up */
+ tem_setparam(tem, 1, 1);
+ tem_mv_cursor(tem, row - tem->tvs_params[0], col);
+ break;
+
+ case 'd': /* VPA - vertical position absolute */
+ tem_setparam(tem, 1, 1);
+ tem_mv_cursor(tem, tem->tvs_params[0] - 1, col);
+ break;
+
+ case 'e': /* VPR - vertical position relative */
+ case 'B': /* cursor down */
+ tem_setparam(tem, 1, 1);
+ tem_mv_cursor(tem, row + tem->tvs_params[0], col);
+ break;
+
+ case 'a': /* HPR - horizontal position relative */
+ case 'C': /* cursor right */
+ tem_setparam(tem, 1, 1);
+ tem_mv_cursor(tem, row, col + tem->tvs_params[0]);
+ break;
+
+ case '`': /* HPA - horizontal position absolute */
+ tem_setparam(tem, 1, 1);
+ tem_mv_cursor(tem, row, tem->tvs_params[0] - 1);
+ break;
+
+ case 'D': /* cursor left */
+ tem_setparam(tem, 1, 1);
+ tem_mv_cursor(tem, row, col - tem->tvs_params[0]);
+ break;
+
+ case 'E': /* CNL cursor next line */
+ tem_setparam(tem, 1, 1);
+ tem_mv_cursor(tem, row + tem->tvs_params[0], 0);
+ break;
+
+ case 'F': /* CPL cursor previous line */
+ tem_setparam(tem, 1, 1);
+ tem_mv_cursor(tem, row - tem->tvs_params[0], 0);
+ break;
+
+ case 'G': /* cursor horizontal position */
+ tem_setparam(tem, 1, 1);
+ tem_mv_cursor(tem, row, tem->tvs_params[0] - 1);
+ break;
+
+ case 'g': /* clear tabs */
+ tem_setparam(tem, 1, 0);
+ tem_clear_tabs(tem, tem->tvs_params[0]);
+ break;
+
+ case 'f': /* HVP Horizontal and Vertical Position */
+ case 'H': /* CUP position cursor */
+ tem_setparam(tem, 2, 1);
+ tem_mv_cursor(tem,
+ tem->tvs_params[0] - 1, tem->tvs_params[1] - 1);
+ break;
+
+ case 'I': /* CHT - Cursor Horizontal Tab */
+ /* Not implemented */
+ break;
+
+ case 'J': /* ED - Erase in Display */
+ tem_send_data(tem);
+ tem_setparam(tem, 1, 0);
+ switch (tem->tvs_params[0]) {
+ case 0:
+ /* erase cursor to end of screen */
+ /* FIRST erase cursor to end of line */
+ tem_clear_chars(tem,
+ tems.ts_c_dimension.width -
+ tem->tvs_c_cursor.col,
+ tem->tvs_c_cursor.row,
+ tem->tvs_c_cursor.col);
+
+ /* THEN erase lines below the cursor */
+ for (row = tem->tvs_c_cursor.row + 1;
+ row < tems.ts_c_dimension.height;
+ row++) {
+ tem_clear_chars(tem,
+ tems.ts_c_dimension.width, row, 0);
+ }
+ break;
+
+ case 1:
+ /* erase beginning of screen to cursor */
+ /* FIRST erase lines above the cursor */
+ for (row = 0;
+ row < tem->tvs_c_cursor.row;
+ row++) {
+ tem_clear_chars(tem,
+ tems.ts_c_dimension.width, row, 0);
+ }
+ /* THEN erase beginning of line to cursor */
+ tem_clear_chars(tem,
+ tem->tvs_c_cursor.col + 1,
+ tem->tvs_c_cursor.row, 0);
+ break;
+
+ case 2:
+ /* erase whole screen */
+ for (row = 0;
+ row < tems.ts_c_dimension.height;
+ row++) {
+ tem_clear_chars(tem,
+ tems.ts_c_dimension.width, row, 0);
+ }
+ break;
+ }
+ break;
+
+ case 'K': /* EL - Erase in Line */
+ tem_send_data(tem);
+ tem_setparam(tem, 1, 0);
+ switch (tem->tvs_params[0]) {
+ case 0:
+ /* erase cursor to end of line */
+ tem_clear_chars(tem,
+ (tems.ts_c_dimension.width -
+ tem->tvs_c_cursor.col),
+ tem->tvs_c_cursor.row,
+ tem->tvs_c_cursor.col);
+ break;
+
+ case 1:
+ /* erase beginning of line to cursor */
+ tem_clear_chars(tem,
+ tem->tvs_c_cursor.col + 1,
+ tem->tvs_c_cursor.row, 0);
+ break;
+
+ case 2:
+ /* erase whole line */
+ tem_clear_chars(tem,
+ tems.ts_c_dimension.width,
+ tem->tvs_c_cursor.row, 0);
+ break;
+ }
+ break;
+
+ case 'L': /* insert line */
+ tem_send_data(tem);
+ tem_setparam(tem, 1, 1);
+ tem_scroll(tem,
+ tem->tvs_c_cursor.row,
+ tems.ts_c_dimension.height - 1,
+ tem->tvs_params[0], TEM_SCROLL_DOWN);
+ break;
+
+ case 'M': /* delete line */
+ tem_send_data(tem);
+ tem_setparam(tem, 1, 1);
+ tem_scroll(tem,
+ tem->tvs_c_cursor.row,
+ tems.ts_c_dimension.height - 1,
+ tem->tvs_params[0], TEM_SCROLL_UP);
+ break;
+
+ case 'P': /* DCH - delete char */
+ tem_setparam(tem, 1, 1);
+ tem_shift(tem, tem->tvs_params[0], TEM_SHIFT_LEFT);
+ break;
+
+ case 'S': /* scroll up */
+ tem_send_data(tem);
+ tem_setparam(tem, 1, 1);
+ tem_scroll(tem, 0,
+ tems.ts_c_dimension.height - 1,
+ tem->tvs_params[0], TEM_SCROLL_UP);
+ break;
+
+ case 'T': /* scroll down */
+ tem_send_data(tem);
+ tem_setparam(tem, 1, 1);
+ tem_scroll(tem, 0,
+ tems.ts_c_dimension.height - 1,
+ tem->tvs_params[0], TEM_SCROLL_DOWN);
+ break;
+
+ case 'X': /* erase char */
+ tem_setparam(tem, 1, 1);
+ tem_clear_chars(tem,
+ tem->tvs_params[0],
+ tem->tvs_c_cursor.row,
+ tem->tvs_c_cursor.col);
+ break;
+
+ case 'Z': /* cursor backward tabulation */
+ tem_setparam(tem, 1, 1);
+
+ /*
+ * Rule exception - We do sanity checking here.
+ *
+ * Restrict the count to a sane value to keep from
+ * looping for a long time. There can't be more than one
+ * tab stop per column, so use that as a limit.
+ */
+ if (tem->tvs_params[0] > tems.ts_c_dimension.width)
+ tem->tvs_params[0] = tems.ts_c_dimension.width;
+
+ for (i = 0; i < tem->tvs_params[0]; i++)
+ tem_back_tab(tem);
+ break;
+ }
+ tem->tvs_state = A_STATE_START;
+}
+
+
+/*
+ * Gather the parameters of an ANSI escape sequence
+ */
+static void
+tem_getparams(struct tem_vt_state *tem, uint8_t ch)
+{
+ if (ch >= '0' && ch <= '9') {
+ tem->tvs_paramval = ((tem->tvs_paramval * 10) + (ch - '0'));
+ tem->tvs_gotparam = B_TRUE; /* Remember got parameter */
+ return; /* Return immediately */
+ } else if (tem->tvs_state == A_STATE_CSI_EQUAL ||
+ tem->tvs_state == A_STATE_CSI_QMARK) {
+ tem->tvs_state = A_STATE_START;
+ } else {
+ if (tem->tvs_curparam < TEM_MAXPARAMS) {
+ if (tem->tvs_gotparam) {
+ /* get the parameter value */
+ tem->tvs_params[tem->tvs_curparam] =
+ tem->tvs_paramval;
+ }
+ tem->tvs_curparam++;
+ }
+
+ if (ch == ';') {
+ /* Restart parameter search */
+ tem->tvs_gotparam = B_FALSE;
+ tem->tvs_paramval = 0; /* No parame value yet */
+ } else {
+ /* Handle escape sequence */
+ tem_chkparam(tem, ch);
+ }
+ }
+}
+
+/*
+ * Add character to internal buffer.
+ * When its full, send it to the next layer.
+ */
+static void
+tem_outch(struct tem_vt_state *tem, tem_char_t ch)
+{
+ text_color_t fg;
+ text_color_t bg;
+ text_attr_t attr;
+
+ /* buffer up the character until later */
+ tem_get_attr(tem, &fg, &bg, &attr, TEM_ATTR_REVERSE);
+ tem->tvs_outbuf[tem->tvs_outindex].tc_char = ch | TEM_ATTR(attr);
+ tem->tvs_outbuf[tem->tvs_outindex].tc_fg_color = fg;
+ tem->tvs_outbuf[tem->tvs_outindex].tc_bg_color = bg;
+ tem->tvs_outindex++;
+ tem->tvs_c_cursor.col++;
+ if (tem->tvs_c_cursor.col >= tems.ts_c_dimension.width) {
+ tem_send_data(tem);
+ tem_new_line(tem);
+ }
+}
+
+static void
+tem_new_line(struct tem_vt_state *tem)
+{
+ tem_cr(tem);
+ tem_lf(tem);
+}
+
+static void
+tem_cr(struct tem_vt_state *tem)
+{
+ tem->tvs_c_cursor.col = 0;
+ tem_align_cursor(tem);
+}
+
+static void
+tem_lf(struct tem_vt_state *tem)
+{
+ int row;
+
+ /*
+ * Sanity checking notes:
+ * . a_nscroll was validated when it was set.
+ * . Regardless of that, tem_scroll and tem_mv_cursor
+ * will prevent anything bad from happening.
+ */
+ row = tem->tvs_c_cursor.row + 1;
+
+ if (row >= tems.ts_c_dimension.height) {
+ if (tem->tvs_nscroll != 0) {
+ tem_scroll(tem, 0,
+ tems.ts_c_dimension.height - 1,
+ tem->tvs_nscroll, TEM_SCROLL_UP);
+ row = tems.ts_c_dimension.height -
+ tem->tvs_nscroll;
+ } else { /* no scroll */
+ /*
+ * implement Esc[#r when # is zero. This means no
+ * scroll but just return cursor to top of screen,
+ * do not clear screen.
+ */
+ row = 0;
+ }
+ }
+
+ tem_mv_cursor(tem, row, tem->tvs_c_cursor.col);
+
+ if (tem->tvs_nscroll == 0) {
+ /* erase rest of cursor line */
+ tem_clear_chars(tem,
+ tems.ts_c_dimension.width -
+ tem->tvs_c_cursor.col,
+ tem->tvs_c_cursor.row,
+ tem->tvs_c_cursor.col);
+
+ }
+
+ tem_align_cursor(tem);
+}
+
+static void
+tem_send_data(struct tem_vt_state *tem)
+{
+ if (tem->tvs_outindex == 0) {
+ tem_align_cursor(tem);
+ return;
+ }
+
+ tem_virtual_display(tem, tem->tvs_outbuf, tem->tvs_outindex,
+ tem->tvs_s_cursor.row, tem->tvs_s_cursor.col);
+
+ if (tem->tvs_isactive) {
+ /*
+ * Call the primitive to render this data.
+ */
+ tem_callback_display(tem,
+ tem->tvs_outbuf, tem->tvs_outindex,
+ tem->tvs_s_cursor.row, tem->tvs_s_cursor.col);
+ }
+
+ tem->tvs_outindex = 0;
+
+ tem_align_cursor(tem);
+}
+
+
+/*
+ * We have just done something to the current output point. Reset the start
+ * point for the buffered data in a_outbuf. There shouldn't be any data
+ * buffered yet.
+ */
+static void
+tem_align_cursor(struct tem_vt_state *tem)
+{
+ tem->tvs_s_cursor.row = tem->tvs_c_cursor.row;
+ tem->tvs_s_cursor.col = tem->tvs_c_cursor.col;
+}
+
+/*
+ * State machine parser based on the current state and character input
+ * major terminations are to control character or normal character
+ */
+
+static void
+tem_parse(struct tem_vt_state *tem, tem_char_t ch)
+{
+ int i;
+
+ if (tem->tvs_state == A_STATE_START) { /* Normal state? */
+ if (ch == A_CSI || ch == A_ESC || ch < ' ') {
+ /* Control */
+ tem_control(tem, ch);
+ } else {
+ /* Display */
+ tem_outch(tem, ch);
+ }
+ return;
+ }
+
+ /* In <ESC> sequence */
+ if (tem->tvs_state != A_STATE_ESC) { /* Need to get parameters? */
+ if (tem->tvs_state != A_STATE_CSI) {
+ tem_getparams(tem, ch);
+ return;
+ }
+
+ switch (ch) {
+ case '?':
+ tem->tvs_state = A_STATE_CSI_QMARK;
+ return;
+ case '=':
+ tem->tvs_state = A_STATE_CSI_EQUAL;
+ return;
+ case 's':
+ /*
+ * As defined below, this sequence
+ * saves the cursor. However, Sun
+ * defines ESC[s as reset. We resolved
+ * the conflict by selecting reset as it
+ * is exported in the termcap file for
+ * sun-mon, while the "save cursor"
+ * definition does not exist anywhere in
+ * /etc/termcap.
+ * However, having no coherent
+ * definition of reset, we have not
+ * implemented it.
+ */
+
+ /*
+ * Original code
+ * tem->tvs_r_cursor.row = tem->tvs_c_cursor.row;
+ * tem->tvs_r_cursor.col = tem->tvs_c_cursor.col;
+ * tem->tvs_state = A_STATE_START;
+ */
+
+ tem->tvs_state = A_STATE_START;
+ return;
+ case 'u':
+ tem_mv_cursor(tem, tem->tvs_r_cursor.row,
+ tem->tvs_r_cursor.col);
+ tem->tvs_state = A_STATE_START;
+ return;
+ case 'p': /* sunbow */
+ tem_send_data(tem);
+ /*
+ * Don't set anything if we are
+ * already as we want to be.
+ */
+ if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) {
+ tem->tvs_flags &= ~TEM_ATTR_SCREEN_REVERSE;
+ /*
+ * If we have switched the characters to be the
+ * inverse from the screen, then switch them as
+ * well to keep them the inverse of the screen.
+ */
+ if (tem->tvs_flags & TEM_ATTR_REVERSE)
+ tem->tvs_flags &= ~TEM_ATTR_REVERSE;
+ else
+ tem->tvs_flags |= TEM_ATTR_REVERSE;
+ }
+ tem_cls(tem);
+ tem->tvs_state = A_STATE_START;
+ return;
+ case 'q': /* sunwob */
+ tem_send_data(tem);
+ /*
+ * Don't set anything if we are
+ * already where as we want to be.
+ */
+ if (!(tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE)) {
+ tem->tvs_flags |= TEM_ATTR_SCREEN_REVERSE;
+ /*
+ * If we have switched the characters to be the
+ * inverse from the screen, then switch them as
+ * well to keep them the inverse of the screen.
+ */
+ if (!(tem->tvs_flags & TEM_ATTR_REVERSE))
+ tem->tvs_flags |= TEM_ATTR_REVERSE;
+ else
+ tem->tvs_flags &= ~TEM_ATTR_REVERSE;
+ }
+
+ tem_cls(tem);
+ tem->tvs_state = A_STATE_START;
+ return;
+ case 'r': /* sunscrl */
+ /*
+ * Rule exception: check for validity here.
+ */
+ tem->tvs_nscroll = tem->tvs_paramval;
+ if (tem->tvs_nscroll > tems.ts_c_dimension.height)
+ tem->tvs_nscroll = tems.ts_c_dimension.height;
+ if (tem->tvs_nscroll < 0)
+ tem->tvs_nscroll = 1;
+ tem->tvs_state = A_STATE_START;
+ return;
+ default:
+ tem_getparams(tem, ch);
+ return;
+ }
+ }
+
+ /* Previous char was <ESC> */
+ if (ch == '[') {
+ tem->tvs_curparam = 0;
+ tem->tvs_paramval = 0;
+ tem->tvs_gotparam = B_FALSE;
+ /* clear the parameters */
+ for (i = 0; i < TEM_MAXPARAMS; i++)
+ tem->tvs_params[i] = -1;
+ tem->tvs_state = A_STATE_CSI;
+ } else if (ch == 'Q') { /* <ESC>Q ? */
+ tem->tvs_state = A_STATE_START;
+ } else if (ch == 'C') { /* <ESC>C ? */
+ tem->tvs_state = A_STATE_START;
+ } else {
+ tem->tvs_state = A_STATE_START;
+ if (ch == 'c') {
+ /* ESC c resets display */
+ tem_reset_display(tem, B_TRUE, B_TRUE);
+ } else if (ch == 'H') {
+ /* ESC H sets a tab */
+ tem_set_tab(tem);
+ } else if (ch == '7') {
+ /* ESC 7 Save Cursor position */
+ tem->tvs_r_cursor.row = tem->tvs_c_cursor.row;
+ tem->tvs_r_cursor.col = tem->tvs_c_cursor.col;
+ } else if (ch == '8') {
+ /* ESC 8 Restore Cursor position */
+ tem_mv_cursor(tem, tem->tvs_r_cursor.row,
+ tem->tvs_r_cursor.col);
+ /* check for control chars */
+ } else if (ch < ' ') {
+ tem_control(tem, ch);
+ } else {
+ tem_outch(tem, ch);
+ }
+ }
+}
+
+/* ARGSUSED */
+static void
+tem_bell(struct tem_vt_state *tem __unused)
+{
+ /* (void) beep(BEEP_CONSOLE); */
+}
+
+
+static void
+tem_scroll(struct tem_vt_state *tem, int start, int end, int count,
+ int direction)
+{
+ int row;
+ int lines_affected;
+
+ lines_affected = end - start + 1;
+ if (count > lines_affected)
+ count = lines_affected;
+ if (count <= 0)
+ return;
+
+ switch (direction) {
+ case TEM_SCROLL_UP:
+ if (count < lines_affected) {
+ tem_copy_area(tem, 0, start + count,
+ tems.ts_c_dimension.width - 1, end, 0, start);
+ }
+ for (row = (end - count) + 1; row <= end; row++) {
+ tem_clear_chars(tem, tems.ts_c_dimension.width, row, 0);
+ }
+ break;
+
+ case TEM_SCROLL_DOWN:
+ if (count < lines_affected) {
+ tem_copy_area(tem, 0, start,
+ tems.ts_c_dimension.width - 1,
+ end - count, 0, start + count);
+ }
+ for (row = start; row < start + count; row++) {
+ tem_clear_chars(tem, tems.ts_c_dimension.width, row, 0);
+ }
+ break;
+ }
+}
+
+static int
+tem_copy_width(term_char_t *src, term_char_t *dst, int cols)
+{
+ int width = cols - 1;
+
+ while (width >= 0) {
+ /* We do not have image bits to compare, stop there. */
+ if (TEM_CHAR_ATTR(src[width].tc_char) == TEM_ATTR_IMAGE ||
+ TEM_CHAR_ATTR(dst[width].tc_char) == TEM_ATTR_IMAGE)
+ break;
+
+ /*
+ * Find difference on line, compare char with its attributes
+ * and colors.
+ */
+ if (src[width].tc_char != dst[width].tc_char ||
+ src[width].tc_fg_color != dst[width].tc_fg_color ||
+ src[width].tc_bg_color != dst[width].tc_bg_color) {
+ break;
+ }
+ width--;
+ }
+ return (width + 1);
+}
+
+static void
+tem_copy_area(struct tem_vt_state *tem,
+ screen_pos_t s_col, screen_pos_t s_row,
+ screen_pos_t e_col, screen_pos_t e_row,
+ screen_pos_t t_col, screen_pos_t t_row)
+{
+ size_t soffset, toffset;
+ term_char_t *src, *dst;
+ int rows;
+ int cols;
+
+ if (s_col < 0 || s_row < 0 ||
+ e_col < 0 || e_row < 0 ||
+ t_col < 0 || t_row < 0 ||
+ s_col >= tems.ts_c_dimension.width ||
+ e_col >= tems.ts_c_dimension.width ||
+ t_col >= tems.ts_c_dimension.width ||
+ s_row >= tems.ts_c_dimension.height ||
+ e_row >= tems.ts_c_dimension.height ||
+ t_row >= tems.ts_c_dimension.height)
+ return;
+
+ if (s_row > e_row || s_col > e_col)
+ return;
+
+ rows = e_row - s_row + 1;
+ cols = e_col - s_col + 1;
+ if (t_row + rows > tems.ts_c_dimension.height ||
+ t_col + cols > tems.ts_c_dimension.width)
+ return;
+
+ if (tem->tvs_screen_buf == NULL) {
+ if (tem->tvs_isactive) {
+ tem_callback_copy(tem, s_col, s_row,
+ e_col, e_row, t_col, t_row);
+ }
+ return;
+ }
+
+ soffset = s_col + s_row * tems.ts_c_dimension.width;
+ toffset = t_col + t_row * tems.ts_c_dimension.width;
+ src = tem->tvs_screen_buf + soffset;
+ dst = tem->tvs_screen_buf + toffset;
+
+ /*
+ * Copy line by line. We determine the length by comparing the
+ * screen content from cached text in tvs_screen_buf.
+ */
+ if (toffset <= soffset) {
+ for (int i = 0; i < rows; i++) {
+ int increment = i * tems.ts_c_dimension.width;
+ int width;
+
+ width = tem_copy_width(src + increment,
+ dst + increment, cols);
+ memmove(dst + increment, src + increment,
+ width * sizeof (term_char_t));
+ if (tem->tvs_isactive) {
+ tem_callback_copy(tem, s_col, s_row + i,
+ e_col - cols + width, s_row + i,
+ t_col, t_row + i);
+ }
+ }
+ } else {
+ for (int i = rows - 1; i >= 0; i--) {
+ int increment = i * tems.ts_c_dimension.width;
+ int width;
+
+ width = tem_copy_width(src + increment,
+ dst + increment, cols);
+ memmove(dst + increment, src + increment,
+ width * sizeof (term_char_t));
+ if (tem->tvs_isactive) {
+ tem_callback_copy(tem, s_col, s_row + i,
+ e_col - cols + width, s_row + i,
+ t_col, t_row + i);
+ }
+ }
+ }
+}
+
+static void
+tem_clear_chars(struct tem_vt_state *tem, int count, screen_pos_t row,
+ screen_pos_t col)
+{
+ if (row < 0 || row >= tems.ts_c_dimension.height ||
+ col < 0 || col >= tems.ts_c_dimension.width ||
+ count < 0)
+ return;
+
+ /*
+ * Note that very large values of "count" could cause col+count
+ * to overflow, so we check "count" independently.
+ */
+ if (count > tems.ts_c_dimension.width ||
+ col + count > tems.ts_c_dimension.width)
+ count = tems.ts_c_dimension.width - col;
+
+ tem_virtual_cls(tem, count, row, col);
+
+ if (!tem->tvs_isactive)
+ return;
+
+ tem_callback_cls(tem, count, row, col);
+}
+
+static void
+tem_text_display(struct tem_vt_state *tem __unused, term_char_t *string,
+ int count, screen_pos_t row, screen_pos_t col)
+{
+ struct vis_consdisplay da;
+ int i;
+ tem_char_t c;
+
+ if (count == 0)
+ return;
+
+ da.data = (unsigned char *)&c;
+ da.width = 1;
+ da.row = row;
+ da.col = col;
+
+ for (i = 0; i < count; i++) {
+ tem_get_color(&da.fg_color, &da.bg_color, string[i]);
+ c = TEM_CHAR(string[i].tc_char);
+ tems_display(&da);
+ da.col++;
+ }
+}
+
+/*
+ * This function is used to mark a rectangular image area so the scrolling
+ * will know we need to copy the data from there.
+ */
+void
+tem_image_display(struct tem_vt_state *tem, screen_pos_t s_row,
+ screen_pos_t s_col, screen_pos_t e_row, screen_pos_t e_col)
+{
+ screen_pos_t i, j;
+ term_char_t c;
+
+ c.tc_char = TEM_ATTR(TEM_ATTR_IMAGE);
+
+ for (i = s_row; i <= e_row; i++) {
+ for (j = s_col; j <= e_col; j++) {
+ tem_virtual_display(tem, &c, 1, i, j);
+ }
+ }
+}
+
+/*ARGSUSED*/
+static void
+tem_text_copy(struct tem_vt_state *tem __unused,
+ screen_pos_t s_col, screen_pos_t s_row,
+ screen_pos_t e_col, screen_pos_t e_row,
+ screen_pos_t t_col, screen_pos_t t_row)
+{
+ struct vis_conscopy da;
+
+ da.s_row = s_row;
+ da.s_col = s_col;
+ da.e_row = e_row;
+ da.e_col = e_col;
+ da.t_row = t_row;
+ da.t_col = t_col;
+ tems_copy(&da);
+}
+
+static void
+tem_text_cls(struct tem_vt_state *tem,
+ int count, screen_pos_t row, screen_pos_t col)
+{
+ text_attr_t attr;
+ term_char_t c;
+ int i;
+
+ tem_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr,
+ TEM_ATTR_SCREEN_REVERSE);
+ c.tc_char = TEM_ATTR(attr & ~TEM_ATTR_UNDERLINE) | ' ';
+
+ if (count > tems.ts_c_dimension.width ||
+ col + count > tems.ts_c_dimension.width)
+ count = tems.ts_c_dimension.width - col;
+
+ for (i = 0; i < count; i++)
+ tem_text_display(tem, &c, 1, row, col++);
+
+}
+
+static void
+tem_pix_display(struct tem_vt_state *tem,
+ term_char_t *string, int count,
+ screen_pos_t row, screen_pos_t col)
+{
+ struct vis_consdisplay da;
+ int i;
+
+ da.data = (uint8_t *)tem->tvs_pix_data;
+ da.width = tems.ts_font.vf_width;
+ da.height = tems.ts_font.vf_height;
+ da.row = (row * da.height) + tems.ts_p_offset.y;
+ da.col = (col * da.width) + tems.ts_p_offset.x;
+
+ for (i = 0; i < count; i++) {
+ tem_callback_bit2pix(tem, string[i]);
+ tems_display(&da);
+ da.col += da.width;
+ }
+}
+
+static void
+tem_pix_copy(struct tem_vt_state *tem,
+ screen_pos_t s_col, screen_pos_t s_row,
+ screen_pos_t e_col, screen_pos_t e_row,
+ screen_pos_t t_col, screen_pos_t t_row)
+{
+ struct vis_conscopy ma;
+ static boolean_t need_clear = B_TRUE;
+
+ if (need_clear && tem->tvs_first_line > 0) {
+ /*
+ * Clear OBP output above our kernel console term
+ * when our kernel console term begins to scroll up,
+ * we hope it is user friendly.
+ * (Also see comments on tem_pix_clear_prom_output)
+ *
+ * This is only one time call.
+ */
+ tem_pix_clear_prom_output(tem);
+ }
+ need_clear = B_FALSE;
+
+ ma.s_row = s_row * tems.ts_font.vf_height + tems.ts_p_offset.y;
+ ma.e_row = (e_row + 1) * tems.ts_font.vf_height +
+ tems.ts_p_offset.y - 1;
+ ma.t_row = t_row * tems.ts_font.vf_height + tems.ts_p_offset.y;
+
+ /*
+ * Check if we're in process of clearing OBP's columns area,
+ * which only happens when term scrolls up a whole line.
+ */
+ if (tem->tvs_first_line > 0 && t_row < s_row && t_col == 0 &&
+ e_col == tems.ts_c_dimension.width - 1) {
+ /*
+ * We need to clear OBP's columns area outside our kernel
+ * console term. So that we set ma.e_col to entire row here.
+ */
+ ma.s_col = s_col * tems.ts_font.vf_width;
+ ma.e_col = tems.ts_p_dimension.width - 1;
+
+ ma.t_col = t_col * tems.ts_font.vf_width;
+ } else {
+ ma.s_col = s_col * tems.ts_font.vf_width + tems.ts_p_offset.x;
+ ma.e_col = (e_col + 1) * tems.ts_font.vf_width +
+ tems.ts_p_offset.x - 1;
+ ma.t_col = t_col * tems.ts_font.vf_width + tems.ts_p_offset.x;
+ }
+
+ tems_copy(&ma);
+
+ if (tem->tvs_first_line > 0 && t_row < s_row) {
+ /* We have scrolled up (s_row - t_row) rows. */
+ tem->tvs_first_line -= (s_row - t_row);
+ if (tem->tvs_first_line <= 0) {
+ /* All OBP rows have been cleared. */
+ tem->tvs_first_line = 0;
+ }
+ }
+}
+
+static void
+tem_pix_bit2pix(struct tem_vt_state *tem, term_char_t c)
+{
+ text_color_t fg, bg;
+ void (*fp)(struct tem_vt_state *, tem_char_t,
+ unsigned char, unsigned char);
+
+ tem_get_color(&fg, &bg, c);
+ switch (tems.ts_pdepth) {
+ case 4:
+ fp = bit_to_pix4;
+ break;
+ case 8:
+ fp = bit_to_pix8;
+ break;
+ case 15:
+ case 16:
+ fp = bit_to_pix16;
+ break;
+ case 24:
+ fp = bit_to_pix24;
+ break;
+ case 32:
+ fp = bit_to_pix32;
+ break;
+ default:
+ return;
+ }
+
+ fp(tem, c.tc_char, fg, bg);
+}
+
+
+/*
+ * This function only clears count of columns in one row
+ */
+static void
+tem_pix_cls(struct tem_vt_state *tem, int count,
+ screen_pos_t row, screen_pos_t col)
+{
+ tem_pix_cls_range(tem, row, 1, tems.ts_p_offset.y,
+ col, count, tems.ts_p_offset.x, B_FALSE);
+}
+
+/*
+ * This function clears OBP output above our kernel console term area
+ * because OBP's term may have a bigger terminal window than that of
+ * our kernel console term. So we need to clear OBP output garbage outside
+ * of our kernel console term at a proper time, which is when the first
+ * row output of our kernel console term scrolls at the first screen line.
+ *
+ * _________________________________
+ * | _____________________ | ---> OBP's bigger term window
+ * | | | |
+ * |___| | |
+ * | | | | |
+ * | | | | |
+ * |_|_|___________________|_______|
+ * | | | ---> first line
+ * | |___________________|---> our kernel console term window
+ * |
+ * |---> columns area to be cleared
+ *
+ * This function only takes care of the output above our kernel console term,
+ * and tem_prom_scroll_up takes care of columns area outside of our kernel
+ * console term.
+ */
+static void
+tem_pix_clear_prom_output(struct tem_vt_state *tem)
+{
+ int nrows, ncols, width, height, offset;
+
+ width = tems.ts_font.vf_width;
+ height = tems.ts_font.vf_height;
+ offset = tems.ts_p_offset.y % height;
+
+ nrows = tems.ts_p_offset.y / height;
+ ncols = (tems.ts_p_dimension.width + (width - 1))/ width;
+
+ if (nrows > 0)
+ tem_pix_cls_range(tem, 0, nrows, offset, 0, ncols, 0,
+ B_FALSE);
+}
+
+/*
+ * Clear the whole screen and reset the cursor to start point.
+ */
+static void
+tem_cls(struct tem_vt_state *tem)
+{
+ struct vis_consclear cl;
+ text_color_t fg_color;
+ text_color_t bg_color;
+ text_attr_t attr;
+ term_char_t c;
+ int row;
+
+ for (row = 0; row < tems.ts_c_dimension.height; row++) {
+ tem_virtual_cls(tem, tems.ts_c_dimension.width, row, 0);
+ }
+
+ if (!tem->tvs_isactive)
+ return;
+
+ tem_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr,
+ TEM_ATTR_SCREEN_REVERSE);
+ c.tc_char = TEM_ATTR(attr);
+
+ tem_get_color(&fg_color, &bg_color, c);
+ cl.bg_color = bg_color;
+ (void)tems_cls(&cl);
+
+ tem->tvs_c_cursor.row = 0;
+ tem->tvs_c_cursor.col = 0;
+ tem_align_cursor(tem);
+}
+
+static void
+tem_back_tab(struct tem_vt_state *tem)
+{
+ int i;
+ screen_pos_t tabstop;
+
+ tabstop = 0;
+
+ for (i = tem->tvs_ntabs - 1; i >= 0; i--) {
+ if (tem->tvs_tabs[i] < tem->tvs_c_cursor.col) {
+ tabstop = tem->tvs_tabs[i];
+ break;
+ }
+ }
+
+ tem_mv_cursor(tem, tem->tvs_c_cursor.row, tabstop);
+}
+
+static void
+tem_tab(struct tem_vt_state *tem)
+{
+ int i;
+ screen_pos_t tabstop;
+
+ tabstop = tems.ts_c_dimension.width - 1;
+
+ for (i = 0; i < tem->tvs_ntabs; i++) {
+ if (tem->tvs_tabs[i] > tem->tvs_c_cursor.col) {
+ tabstop = tem->tvs_tabs[i];
+ break;
+ }
+ }
+
+ tem_mv_cursor(tem, tem->tvs_c_cursor.row, tabstop);
+}
+
+static void
+tem_set_tab(struct tem_vt_state *tem)
+{
+ int i;
+ int j;
+
+ if (tem->tvs_ntabs == TEM_MAXTAB)
+ return;
+ if (tem->tvs_ntabs == 0 ||
+ tem->tvs_tabs[tem->tvs_ntabs] < tem->tvs_c_cursor.col) {
+ tem->tvs_tabs[tem->tvs_ntabs++] = tem->tvs_c_cursor.col;
+ return;
+ }
+ for (i = 0; i < tem->tvs_ntabs; i++) {
+ if (tem->tvs_tabs[i] == tem->tvs_c_cursor.col)
+ return;
+ if (tem->tvs_tabs[i] > tem->tvs_c_cursor.col) {
+ for (j = tem->tvs_ntabs - 1; j >= i; j--)
+ tem->tvs_tabs[j+ 1] = tem->tvs_tabs[j];
+ tem->tvs_tabs[i] = tem->tvs_c_cursor.col;
+ tem->tvs_ntabs++;
+ return;
+ }
+ }
+}
+
+static void
+tem_clear_tabs(struct tem_vt_state *tem, int action)
+{
+ int i;
+ int j;
+
+ switch (action) {
+ case 3: /* clear all tabs */
+ tem->tvs_ntabs = 0;
+ break;
+ case 0: /* clr tab at cursor */
+
+ for (i = 0; i < tem->tvs_ntabs; i++) {
+ if (tem->tvs_tabs[i] == tem->tvs_c_cursor.col) {
+ tem->tvs_ntabs--;
+ for (j = i; j < tem->tvs_ntabs; j++)
+ tem->tvs_tabs[j] = tem->tvs_tabs[j + 1];
+ return;
+ }
+ }
+ break;
+ }
+}
+
+static void
+tem_mv_cursor(struct tem_vt_state *tem, int row, int col)
+{
+ /*
+ * Sanity check and bounds enforcement. Out of bounds requests are
+ * clipped to the screen boundaries. This seems to be what SPARC
+ * does.
+ */
+ if (row < 0)
+ row = 0;
+ if (row >= tems.ts_c_dimension.height)
+ row = tems.ts_c_dimension.height - 1;
+ if (col < 0)
+ col = 0;
+ if (col >= tems.ts_c_dimension.width)
+ col = tems.ts_c_dimension.width - 1;
+
+ tem_send_data(tem);
+ tem->tvs_c_cursor.row = (screen_pos_t)row;
+ tem->tvs_c_cursor.col = (screen_pos_t)col;
+ tem_align_cursor(tem);
+}
+
+/* ARGSUSED */
+static void
+tem_reset_emulator(struct tem_vt_state *tem, boolean_t init_color)
+{
+ int j;
+
+ tem->tvs_c_cursor.row = 0;
+ tem->tvs_c_cursor.col = 0;
+ tem->tvs_r_cursor.row = 0;
+ tem->tvs_r_cursor.col = 0;
+ tem->tvs_s_cursor.row = 0;
+ tem->tvs_s_cursor.col = 0;
+ tem->tvs_outindex = 0;
+ tem->tvs_state = A_STATE_START;
+ tem->tvs_gotparam = B_FALSE;
+ tem->tvs_curparam = 0;
+ tem->tvs_paramval = 0;
+ tem->tvs_nscroll = 1;
+
+ if (init_color) {
+ /* use initial settings */
+ tem->tvs_fg_color = tems.ts_init_color.fg_color;
+ tem->tvs_bg_color = tems.ts_init_color.bg_color;
+ tem->tvs_flags = tems.ts_init_color.a_flags;
+ }
+
+ /*
+ * set up the initial tab stops
+ */
+ tem->tvs_ntabs = 0;
+ for (j = 8; j < tems.ts_c_dimension.width; j += 8)
+ tem->tvs_tabs[tem->tvs_ntabs++] = (screen_pos_t)j;
+
+ for (j = 0; j < TEM_MAXPARAMS; j++)
+ tem->tvs_params[j] = 0;
+}
+
+static void
+tem_reset_display(struct tem_vt_state *tem,
+ boolean_t clear_txt, boolean_t init_color)
+{
+ tem_reset_emulator(tem, init_color);
+
+ if (clear_txt) {
+ if (tem->tvs_isactive)
+ tem_callback_cursor(tem, VIS_HIDE_CURSOR);
+
+ tem_cls(tem);
+
+ if (tem->tvs_isactive)
+ tem_callback_cursor(tem, VIS_DISPLAY_CURSOR);
+ }
+}
+
+static void
+tem_shift(struct tem_vt_state *tem, int count, int direction)
+{
+ int rest_of_line;
+
+ rest_of_line = tems.ts_c_dimension.width - tem->tvs_c_cursor.col;
+ if (count > rest_of_line)
+ count = rest_of_line;
+
+ if (count <= 0)
+ return;
+
+ switch (direction) {
+ case TEM_SHIFT_LEFT:
+ if (count < rest_of_line) {
+ tem_copy_area(tem,
+ tem->tvs_c_cursor.col + count,
+ tem->tvs_c_cursor.row,
+ tems.ts_c_dimension.width - 1,
+ tem->tvs_c_cursor.row,
+ tem->tvs_c_cursor.col,
+ tem->tvs_c_cursor.row);
+ }
+
+ tem_clear_chars(tem, count, tem->tvs_c_cursor.row,
+ (tems.ts_c_dimension.width - count));
+ break;
+ case TEM_SHIFT_RIGHT:
+ if (count < rest_of_line) {
+ tem_copy_area(tem,
+ tem->tvs_c_cursor.col,
+ tem->tvs_c_cursor.row,
+ tems.ts_c_dimension.width - count - 1,
+ tem->tvs_c_cursor.row,
+ tem->tvs_c_cursor.col + count,
+ tem->tvs_c_cursor.row);
+ }
+
+ tem_clear_chars(tem, count, tem->tvs_c_cursor.row,
+ tem->tvs_c_cursor.col);
+ break;
+ }
+}
+
+static void
+tem_text_cursor(struct tem_vt_state *tem, short action)
+{
+ struct vis_conscursor ca;
+
+ ca.row = tem->tvs_c_cursor.row;
+ ca.col = tem->tvs_c_cursor.col;
+ ca.action = action;
+
+ tems_cursor(&ca);
+
+ if (action == VIS_GET_CURSOR) {
+ tem->tvs_c_cursor.row = ca.row;
+ tem->tvs_c_cursor.col = ca.col;
+ }
+}
+
+static void
+tem_pix_cursor(struct tem_vt_state *tem, short action)
+{
+ struct vis_conscursor ca;
+ uint32_t color;
+ text_color_t fg, bg;
+ term_char_t c;
+ text_attr_t attr;
+
+ ca.row = tem->tvs_c_cursor.row * tems.ts_font.vf_height +
+ tems.ts_p_offset.y;
+ ca.col = tem->tvs_c_cursor.col * tems.ts_font.vf_width +
+ tems.ts_p_offset.x;
+ ca.width = tems.ts_font.vf_width;
+ ca.height = tems.ts_font.vf_height;
+
+ tem_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr,
+ TEM_ATTR_REVERSE);
+ c.tc_char = TEM_ATTR(attr);
+
+ tem_get_color(&fg, &bg, c);
+
+ switch (tems.ts_pdepth) {
+ case 4:
+ ca.fg_color.mono = fg;
+ ca.bg_color.mono = bg;
+ break;
+ case 8:
+ ca.fg_color.mono = tems.ts_color_map(fg);
+ ca.bg_color.mono = tems.ts_color_map(bg);
+ break;
+ case 15:
+ case 16:
+ color = tems.ts_color_map(fg);
+ ca.fg_color.sixteen[0] = (color >> 8) & 0xFF;
+ ca.fg_color.sixteen[1] = color & 0xFF;
+ color = tems.ts_color_map(bg);
+ ca.bg_color.sixteen[0] = (color >> 8) & 0xFF;
+ ca.bg_color.sixteen[1] = color & 0xFF;
+ break;
+ case 24:
+ case 32:
+ color = tems.ts_color_map(fg);
+ ca.fg_color.twentyfour[0] = (color >> 16) & 0xFF;
+ ca.fg_color.twentyfour[1] = (color >> 8) & 0xFF;
+ ca.fg_color.twentyfour[2] = color & 0xFF;
+ color = tems.ts_color_map(bg);
+ ca.bg_color.twentyfour[0] = (color >> 16) & 0xFF;
+ ca.bg_color.twentyfour[1] = (color >> 8) & 0xFF;
+ ca.bg_color.twentyfour[2] = color & 0xFF;
+ break;
+ }
+
+ ca.action = action;
+
+ tems_cursor(&ca);
+
+ if (action == VIS_GET_CURSOR) {
+ tem->tvs_c_cursor.row = 0;
+ tem->tvs_c_cursor.col = 0;
+
+ if (ca.row != 0) {
+ tem->tvs_c_cursor.row = (ca.row - tems.ts_p_offset.y) /
+ tems.ts_font.vf_height;
+ }
+ if (ca.col != 0) {
+ tem->tvs_c_cursor.col = (ca.col - tems.ts_p_offset.x) /
+ tems.ts_font.vf_width;
+ }
+ }
+}
+
+static void
+bit_to_pix4(struct tem_vt_state *tem,
+ tem_char_t c,
+ text_color_t fg_color,
+ text_color_t bg_color)
+{
+ uint8_t *dest = (uint8_t *)tem->tvs_pix_data;
+ font_bit_to_pix4(&tems.ts_font, dest, c, fg_color, bg_color);
+}
+
+static void
+bit_to_pix8(struct tem_vt_state *tem,
+ tem_char_t c,
+ text_color_t fg_color,
+ text_color_t bg_color)
+{
+ uint8_t *dest = (uint8_t *)tem->tvs_pix_data;
+
+ fg_color = (text_color_t)tems.ts_color_map(fg_color);
+ bg_color = (text_color_t)tems.ts_color_map(bg_color);
+ font_bit_to_pix8(&tems.ts_font, dest, c, fg_color, bg_color);
+}
+
+static void
+bit_to_pix16(struct tem_vt_state *tem,
+ tem_char_t c,
+ text_color_t fg_color4,
+ text_color_t bg_color4)
+{
+ uint16_t fg_color16, bg_color16;
+ uint16_t *dest;
+
+ fg_color16 = (uint16_t)tems.ts_color_map(fg_color4);
+ bg_color16 = (uint16_t)tems.ts_color_map(bg_color4);
+
+ dest = (uint16_t *)tem->tvs_pix_data;
+ font_bit_to_pix16(&tems.ts_font, dest, c, fg_color16, bg_color16);
+}
+
+static void
+bit_to_pix24(struct tem_vt_state *tem,
+ tem_char_t c,
+ text_color_t fg_color4,
+ text_color_t bg_color4)
+{
+ uint32_t fg_color32, bg_color32;
+ uint8_t *dest;
+
+ fg_color32 = tems.ts_color_map(fg_color4);
+ bg_color32 = tems.ts_color_map(bg_color4);
+
+ dest = (uint8_t *)tem->tvs_pix_data;
+ font_bit_to_pix24(&tems.ts_font, dest, c, fg_color32, bg_color32);
+}
+
+static void
+bit_to_pix32(struct tem_vt_state *tem,
+ tem_char_t c,
+ text_color_t fg_color4,
+ text_color_t bg_color4)
+{
+ uint32_t fg_color32, bg_color32, *dest;
+
+ fg_color32 = (0xFF << 24) | tems.ts_color_map(fg_color4);
+ bg_color32 = (0xFF << 24) | tems.ts_color_map(bg_color4);
+
+ dest = (uint32_t *)tem->tvs_pix_data;
+ font_bit_to_pix32(&tems.ts_font, dest, c, fg_color32, bg_color32);
+}
+
+/*
+ * flag: TEM_ATTR_SCREEN_REVERSE or TEM_ATTR_REVERSE
+ */
+static void
+tem_get_attr(struct tem_vt_state *tem, text_color_t *fg,
+ text_color_t *bg, text_attr_t *attr, uint8_t flag)
+{
+ if (tem->tvs_flags & flag) {
+ *fg = tem->tvs_bg_color;
+ *bg = tem->tvs_fg_color;
+ } else {
+ *fg = tem->tvs_fg_color;
+ *bg = tem->tvs_bg_color;
+ }
+
+ if (attr == NULL)
+ return;
+
+ *attr = tem->tvs_flags;
+}
+
+static void
+tem_get_color(text_color_t *fg, text_color_t *bg, term_char_t c)
+{
+ if (TEM_CHAR_ATTR(c.tc_char) & (TEM_ATTR_BRIGHT_FG | TEM_ATTR_BOLD))
+ *fg = brt_xlate[c.tc_fg_color];
+ else
+ *fg = dim_xlate[c.tc_fg_color];
+
+ if (TEM_CHAR_ATTR(c.tc_char) & TEM_ATTR_BRIGHT_BG)
+ *bg = brt_xlate[c.tc_bg_color];
+ else
+ *bg = dim_xlate[c.tc_bg_color];
+}
+
+void
+tem_get_colors(tem_vt_state_t tem_arg, text_color_t *fg, text_color_t *bg)
+{
+ struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg;
+ text_attr_t attr;
+ term_char_t c;
+
+ tem_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr,
+ TEM_ATTR_REVERSE);
+ c.tc_char = TEM_ATTR(attr);
+ tem_get_color(fg, bg, c);
+}
+
+/*
+ * Clear a rectangle of screen for pixel mode.
+ *
+ * arguments:
+ * row: start row#
+ * nrows: the number of rows to clear
+ * offset_y: the offset of height in pixels to begin clear
+ * col: start col#
+ * ncols: the number of cols to clear
+ * offset_x: the offset of width in pixels to begin clear
+ * scroll_up: whether this function is called during sroll up,
+ * which is called only once.
+ */
+static void
+tem_pix_cls_range(struct tem_vt_state *tem,
+ screen_pos_t row, int nrows, int offset_y,
+ screen_pos_t col, int ncols, int offset_x,
+ boolean_t sroll_up)
+{
+ struct vis_consdisplay da;
+ int i, j;
+ int row_add = 0;
+ term_char_t c;
+ text_attr_t attr;
+
+ if (sroll_up)
+ row_add = tems.ts_c_dimension.height - 1;
+
+ da.width = tems.ts_font.vf_width;
+ da.height = tems.ts_font.vf_height;
+
+ tem_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr,
+ TEM_ATTR_SCREEN_REVERSE);
+ /* Make sure we will not draw underlines */
+ c.tc_char = TEM_ATTR(attr & ~TEM_ATTR_UNDERLINE) | ' ';
+
+ tem_callback_bit2pix(tem, c);
+ da.data = (uint8_t *)tem->tvs_pix_data;
+
+ for (i = 0; i < nrows; i++, row++) {
+ da.row = (row + row_add) * da.height + offset_y;
+ da.col = col * da.width + offset_x;
+ for (j = 0; j < ncols; j++) {
+ tems_display(&da);
+ da.col += da.width;
+ }
+ }
+}
+
+/*
+ * virtual screen operations
+ */
+static void
+tem_virtual_display(struct tem_vt_state *tem, term_char_t *string,
+ size_t count, screen_pos_t row, screen_pos_t col)
+{
+ size_t i, width;
+ term_char_t *addr;
+
+ if (tem->tvs_screen_buf == NULL)
+ return;
+
+ if (row < 0 || row >= tems.ts_c_dimension.height ||
+ col < 0 || col >= tems.ts_c_dimension.width ||
+ col + count > (size_t)tems.ts_c_dimension.width)
+ return;
+
+ width = tems.ts_c_dimension.width;
+ addr = tem->tvs_screen_buf + (row * width + col);
+ for (i = 0; i < count; i++) {
+ *addr++ = string[i];
+ }
+}
+
+static void
+tem_virtual_cls(struct tem_vt_state *tem, size_t count,
+ screen_pos_t row, screen_pos_t col)
+{
+ term_char_t c;
+
+ c.tc_char = ' ';
+ tem_get_colors((tem_vt_state_t)tem, &c.tc_fg_color, &c.tc_bg_color);
+
+ while (count > 0) {
+ tem_virtual_display(tem, &c, 1, row, col);
+ col++;
+ count--;
+ }
+}
diff --git a/usr/src/boot/sys/boot/efi/Makefile.inc b/usr/src/boot/sys/boot/efi/Makefile.inc
index d25885fd01..7fbe2a3393 100644
--- a/usr/src/boot/sys/boot/efi/Makefile.inc
+++ b/usr/src/boot/sys/boot/efi/Makefile.inc
@@ -14,6 +14,7 @@
#
BINDIR= /boot
+PNGLITE=$(SRC)/common/pnglite
# Options used when building app-specific efi components
# See conf/kern.mk for the correct set of these
diff --git a/usr/src/boot/sys/boot/efi/include/eficon.h b/usr/src/boot/sys/boot/efi/include/eficon.h
index 1d0c869f47..b5a387cb08 100644
--- a/usr/src/boot/sys/boot/efi/include/eficon.h
+++ b/usr/src/boot/sys/boot/efi/include/eficon.h
@@ -263,28 +263,56 @@ typedef struct {
// Scan codes for base line keys
//
-#define SCAN_NULL 0x0000
-#define SCAN_UP 0x0001
-#define SCAN_DOWN 0x0002
-#define SCAN_RIGHT 0x0003
-#define SCAN_LEFT 0x0004
-#define SCAN_HOME 0x0005
-#define SCAN_END 0x0006
-#define SCAN_INSERT 0x0007
-#define SCAN_DELETE 0x0008
-#define SCAN_PAGE_UP 0x0009
-#define SCAN_PAGE_DOWN 0x000A
-#define SCAN_F1 0x000B
-#define SCAN_F2 0x000C
-#define SCAN_F3 0x000D
-#define SCAN_F4 0x000E
-#define SCAN_F5 0x000F
-#define SCAN_F6 0x0010
-#define SCAN_F7 0x0011
-#define SCAN_F8 0x0012
-#define SCAN_F9 0x0013
-#define SCAN_F10 0x0014
-#define SCAN_ESC 0x0017
+#define SCAN_NULL 0x0000
+#define SCAN_UP 0x0001
+#define SCAN_DOWN 0x0002
+#define SCAN_RIGHT 0x0003
+#define SCAN_LEFT 0x0004
+#define SCAN_HOME 0x0005
+#define SCAN_END 0x0006
+#define SCAN_INSERT 0x0007
+#define SCAN_DELETE 0x0008
+#define SCAN_PAGE_UP 0x0009
+#define SCAN_PAGE_DOWN 0x000A
+#define SCAN_F1 0x000B
+#define SCAN_F2 0x000C
+#define SCAN_F3 0x000D
+#define SCAN_F4 0x000E
+#define SCAN_F5 0x000F
+#define SCAN_F6 0x0010
+#define SCAN_F7 0x0011
+#define SCAN_F8 0x0012
+#define SCAN_F9 0x0013
+#define SCAN_F10 0x0014
+#define SCAN_ESC 0x0017
+
+//
+// EFI Scan code Ex
+//
+#define SCAN_F11 0x0015
+#define SCAN_F12 0x0016
+#define SCAN_F13 0x0068
+#define SCAN_F14 0x0069
+#define SCAN_F15 0x006A
+#define SCAN_F16 0x006B
+#define SCAN_F17 0x006C
+#define SCAN_F18 0x006D
+#define SCAN_F19 0x006E
+#define SCAN_F20 0x006F
+#define SCAN_F21 0x0070
+#define SCAN_F22 0x0071
+#define SCAN_F23 0x0072
+#define SCAN_F24 0x0073
+#define SCAN_MUTE 0x007F
+#define SCAN_VOLUME_UP 0x0080
+#define SCAN_VOLUME_DOWN 0x0081
+#define SCAN_BRIGHTNESS_UP 0x0100
+#define SCAN_BRIGHTNESS_DOWN 0x0101
+#define SCAN_SUSPEND 0x0102
+#define SCAN_HIBERNATE 0x0103
+#define SCAN_TOGGLE_DISPLAY 0x0104
+#define SCAN_RECOVERY 0x0105
+#define SCAN_EJECT 0x0106
typedef
EFI_STATUS
@@ -310,4 +338,190 @@ typedef struct _SIMPLE_INPUT_INTERFACE {
{0xdd9e7534, 0x7762, 0x4698, {0x8c, 0x14, 0xf5, 0x85, \
0x17, 0xa6, 0x25, 0xaa} }
+INTERFACE_DECL(_EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL);
+
+typedef UINT8 EFI_KEY_TOGGLE_STATE;
+//
+// Any Shift or Toggle State that is valid should have
+// high order bit set.
+//
+typedef struct EFI_KEY_STATE {
+ UINT32 KeyShiftState;
+ EFI_KEY_TOGGLE_STATE KeyToggleState;
+} EFI_KEY_STATE;
+
+typedef struct {
+ EFI_INPUT_KEY Key;
+ EFI_KEY_STATE KeyState;
+} EFI_KEY_DATA;
+
+//
+// Shift state
+//
+#define EFI_SHIFT_STATE_VALID 0x80000000
+#define EFI_RIGHT_SHIFT_PRESSED 0x00000001
+#define EFI_LEFT_SHIFT_PRESSED 0x00000002
+#define EFI_RIGHT_CONTROL_PRESSED 0x00000004
+#define EFI_LEFT_CONTROL_PRESSED 0x00000008
+#define EFI_RIGHT_ALT_PRESSED 0x00000010
+#define EFI_LEFT_ALT_PRESSED 0x00000020
+#define EFI_RIGHT_LOGO_PRESSED 0x00000040
+#define EFI_LEFT_LOGO_PRESSED 0x00000080
+#define EFI_MENU_KEY_PRESSED 0x00000100
+#define EFI_SYS_REQ_PRESSED 0x00000200
+
+//
+// Toggle state
+//
+#define EFI_TOGGLE_STATE_VALID 0x80
+#define EFI_KEY_STATE_EXPOSED 0x40
+#define EFI_SCROLL_LOCK_ACTIVE 0x01
+#define EFI_NUM_LOCK_ACTIVE 0x02
+#define EFI_CAPS_LOCK_ACTIVE 0x04
+
+//
+// EFI Key Notfication Function
+//
+typedef
+EFI_STATUS
+(EFIAPI *EFI_KEY_NOTIFY_FUNCTION) (
+ IN EFI_KEY_DATA *KeyData
+ );
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_INPUT_RESET_EX) (
+ IN struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+/*++
+
+ Routine Description:
+ Reset the input device and optionaly run diagnostics
+
+ Arguments:
+ This - Protocol instance pointer.
+ ExtendedVerification - Driver may perform diagnostics on reset.
+
+ Returns:
+ EFI_SUCCESS - The device was reset.
+ EFI_DEVICE_ERROR - The device is not functioning properly and could
+ not be reset.
+
+--*/
+;
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_INPUT_READ_KEY_EX) (
+ IN struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ OUT EFI_KEY_DATA *KeyData
+ )
+/*++
+
+ Routine Description:
+ Reads the next keystroke from the input device. The WaitForKey Event can
+ be used to test for existance of a keystroke via WaitForEvent () call.
+
+ Arguments:
+ This - Protocol instance pointer.
+ KeyData - A pointer to a buffer that is filled in with the keystroke
+ state data for the key that was pressed.
+
+ Returns:
+ EFI_SUCCESS - The keystroke information was returned.
+ EFI_NOT_READY - There was no keystroke data availiable.
+ EFI_DEVICE_ERROR - The keystroke information was not returned due to
+ hardware errors.
+ EFI_INVALID_PARAMETER - KeyData is NULL.
+--*/
+;
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SET_STATE) (
+ IN struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_KEY_TOGGLE_STATE *KeyToggleState
+ )
+/*++
+
+ Routine Description:
+ Set certain state for the input device.
+
+ Arguments:
+ This - Protocol instance pointer.
+ KeyToggleState - A pointer to the EFI_KEY_TOGGLE_STATE to set the
+ state for the input device.
+
+ Returns:
+ EFI_SUCCESS - The device state was set successfully.
+ EFI_DEVICE_ERROR - The device is not functioning correctly and could
+ not have the setting adjusted.
+ EFI_UNSUPPORTED - The device does not have the ability to set its state.
+ EFI_INVALID_PARAMETER - KeyToggleState is NULL.
+
+--*/
+;
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_REGISTER_KEYSTROKE_NOTIFY) (
+ IN struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_KEY_DATA *KeyData,
+ IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,
+ OUT EFI_HANDLE *NotifyHandle
+ )
+/*++
+
+ Routine Description:
+ Register a notification function for a particular keystroke for the input device.
+
+ Arguments:
+ This - Protocol instance pointer.
+ KeyData - A pointer to a buffer that is filled in with the keystroke
+ information data for the key that was pressed.
+ KeyNotificationFunction - Points to the function to be called when the key
+ sequence is typed specified by KeyData.
+ NotifyHandle - Points to the unique handle assigned to the registered notification.
+
+ Returns:
+ EFI_SUCCESS - The notification function was registered successfully.
+ EFI_OUT_OF_RESOURCES - Unable to allocate resources for necesssary data structures.
+ EFI_INVALID_PARAMETER - KeyData or NotifyHandle is NULL.
+
+--*/
+;
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_UNREGISTER_KEYSTROKE_NOTIFY) (
+ IN struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_HANDLE NotificationHandle
+ )
+/*++
+
+ Routine Description:
+ Remove a registered notification function from a particular keystroke.
+
+ Arguments:
+ This - Protocol instance pointer.
+ NotificationHandle - The handle of the notification function being unregistered.
+
+ Returns:
+ EFI_SUCCESS - The notification function was unregistered successfully.
+ EFI_INVALID_PARAMETER - The NotificationHandle is invalid.
+ EFI_NOT_FOUND - Can not find the matching entry in database.
+
+--*/
+;
+
+typedef struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL {
+ EFI_INPUT_RESET_EX Reset;
+ EFI_INPUT_READ_KEY_EX ReadKeyStrokeEx;
+ EFI_EVENT WaitForKeyEx;
+ EFI_SET_STATE SetState;
+ EFI_REGISTER_KEYSTROKE_NOTIFY RegisterKeyNotify;
+ EFI_UNREGISTER_KEYSTROKE_NOTIFY UnregisterKeyNotify;
+} EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL;
+
#endif
diff --git a/usr/src/boot/sys/boot/efi/libefi/Makefile.com b/usr/src/boot/sys/boot/efi/libefi/Makefile.com
index 1c5a91b664..4ba5dbf537 100644
--- a/usr/src/boot/sys/boot/efi/libefi/Makefile.com
+++ b/usr/src/boot/sys/boot/efi/libefi/Makefile.com
@@ -31,13 +31,17 @@ SRCS += delay.c \
efizfs.c \
env.c \
errno.c \
+ gfx_fb.c \
handles.c \
libefi.c \
+ pnglite.c \
wchar.c
OBJS= $(SRCS:%.c=%.o)
-CPPFLAGS= -D_STANDALONE
+PNGLITE=$(SRC)/common/pnglite
+
+CPPFLAGS= -D_STANDALONE -DEFI
CFLAGS = -Os
CPPFLAGS += -nostdinc -I. -I../../../../../include -I../../../..
@@ -47,13 +51,17 @@ CPPFLAGS += -I../../include/$(MACHINE)
CPPFLAGS += -I../../../../../lib/libstand
CPPFLAGS += -I../../../zfs
CPPFLAGS += -I../../../../cddl/boot/zfs
+CPPFLAGS += -I../../../../../lib/libz
+CPPFLAGS += -I$(PNGLITE)
# Pick up the bootstrap header for some interface items
CPPFLAGS += -I../../../common
-CPPFLAGS += -DTERM_EMU
include ../../Makefile.inc
+# For multiboot2.h, must be last, to avoid conflicts
+CPPFLAGS += -I$(SRC)/uts/common
+
libefi.a: $(OBJS)
$(AR) $(ARFLAGS) $@ $(OBJS)
@@ -71,3 +79,9 @@ x86:
%.o: ../%.c
$(COMPILE.c) $<
+
+%.o: ../../../common/%.c
+ $(COMPILE.c) $<
+
+%.o: $(PNGLITE)/%.c
+ $(COMPILE.c) $<
diff --git a/usr/src/boot/sys/boot/efi/libefi/efi_console.c b/usr/src/boot/sys/boot/efi/libefi/efi_console.c
index 2f504431f3..d17ee134a6 100644
--- a/usr/src/boot/sys/boot/efi/libefi/efi_console.c
+++ b/usr/src/boot/sys/boot/efi/libefi/efi_console.c
@@ -28,469 +28,535 @@
#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_CONSOLE_CONTROL_SCREEN_MODE console_mode;
static SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
-static SIMPLE_INPUT_INTERFACE *conin;
-#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;
+
+struct efi_console_data {
+ struct visual_ops *ecd_visual_ops;
+ SIMPLE_INPUT_INTERFACE *ecd_conin;
+ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *ecd_coninex;
+};
-#define MAXARGS 8
#define KEYBUFSZ 10
static unsigned keybuf[KEYBUFSZ]; /* keybuf for extended codes */
+
static int key_pending;
-static int args[MAXARGS], argc;
-static int fg_c, bg_c;
-static UINTN curx, cury;
-static int esc;
+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
+};
-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
+#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" };
+
+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
+};
-/* Get cursor position. */
-void
-get_pos(UINTN *x, UINTN *y)
+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)
{
- *x = conout->Mode->CursorColumn;
- *y = conout->Mode->CursorRow;
+ return (console_mode == EfiConsoleControlScreenGraphics);
}
-/* Move cursor to x rows and y cols (0-based). */
void
-curs_move(UINTN *_x, UINTN *_y, UINTN x, UINTN y)
+plat_tem_hide_prom_cursor(void)
{
- conout->SetCursorPosition(conout, x, y);
- if (_x != NULL)
- *_x = conout->Mode->CursorColumn;
- if (_y != NULL)
- *_y = conout->Mode->CursorRow;
+ conout->EnableCursor(conout, FALSE);
+}
+
+static void
+plat_tem_display_prom_cursor(screen_pos_t row, screen_pos_t col)
+{
+
+ conout->SetCursorPosition(conout, col, row);
+ conout->EnableCursor(conout, TRUE);
}
-/* Clear internal state of the terminal emulation code. */
void
-end_term(void)
+plat_tem_get_prom_pos(uint32_t *row, uint32_t *col)
{
- esc = 0;
- argc = -1;
+ if (console_mode == EfiConsoleControlScreenText) {
+ *col = (uint32_t)conout->Mode->CursorColumn;
+ *row = (uint32_t)conout->Mode->CursorRow;
+ } else {
+ *col = 0;
+ *row = 0;
+ }
}
-#endif
+/*
+ * 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
+plat_tem_get_prom_size(size_t *height, size_t *width)
+{
+ 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;
+ }
+}
-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;
+ UINTN cols, rows;
+ struct vis_devinit devinit;
+ struct efi_console_data *ecd = efi_console.c_private;
+
+ /* 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;
+ ecd->ecd_visual_ops = &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;
+ ecd->ecd_visual_ops = &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;
-
- 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
- }
+ UINTN cols, rows;
+
+ 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;
-/* Home cursor (left top corner), also called from mode command. */
-void
-HO(void)
-{
- argc = 1;
- args[0] = args[1] = 1;
- CM();
+ (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]);
}
-/* Clear line from current position to end of line */
-static void
-CL(int direction)
+static void efi_cons_cursor(struct vis_conscursor *cc)
{
- 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;
+ 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 1: /* from beginning to cursor */
- len = curx;
+ case VIS_DISPLAY_CURSOR:
+ if (plat_stdout_is_framebuffer())
+ gfx_fb_display_cursor(cc);
+ else
+ plat_tem_display_prom_cursor(cc->row, cc->col);
break;
- case 2: /* entire line */
- default:
- len = x;
+ 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;
}
+}
- if (cury == y - 1)
- len--;
+static int
+efi_cons_ioctl(struct console *cp, int cmd, void *data)
+{
+ struct efi_console_data *ecd = cp->c_private;
+ struct visual_ops *ops = ecd->ecd_visual_ops;
- line = malloc(len * sizeof (CHAR16));
- if (line == NULL) {
- printf("out of memory\n");
- return;
+ switch (cmd) {
+ case VIS_GETIDENTIFIER:
+ memmove(data, ops->ident, sizeof (struct vis_identifier));
+ break;
+ case VIS_DEVINIT:
+ return (ops->devinit(data));
+ case VIS_CONSCLEAR:
+ return (ops->cons_clear(data));
+ case VIS_CONSCOPY:
+ ops->cons_copy(data);
+ break;
+ case VIS_CONSDISPLAY:
+ ops->cons_display(data);
+ break;
+ case VIS_CONSCURSOR:
+ ops->cons_cursor(data);
+ break;
+ default:
+ return (EINVAL);
}
- 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();
+ return (0);
}
static void
-get_arg(int c)
+efi_framebuffer_setup(void)
{
- if (argc < 0)
- argc = 0;
- args[argc] *= 10;
- args[argc] += c - '0';
+ int bpp, pos;
+
+ bpp = fls(efifb.fb_mask_red | efifb.fb_mask_green |
+ efifb.fb_mask_blue | efifb.fb_mask_reserved);
+
+ 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;
+
+ 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;
}
-/* Emulate basic capabilities of sun-color terminal */
static void
-efi_term_emu(int c)
+efi_cons_probe(struct console *cp)
{
- static int ansi_col[] = {
- 0, 4, 2, 6, 1, 5, 3, 7
- };
- int t, i;
-
- 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 '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;
- }
- 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;
- }
- }
- 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;
+ struct efi_console_data *ecd;
+ EFI_STATUS status;
+ UINTN i, max_dim, best_mode, cols, rows;
+
+ ecd = calloc(1, sizeof (*ecd));
+ /*
+ * As console probing is called very early, the only reason for
+ * out of memory can be that we just do not have enough memory.
+ */
+ if (ecd == NULL)
+ panic("efi_cons_probe: This system has not enough memory\n");
+ cp->c_private = ecd;
+
+ conout = ST->ConOut;
+ ecd->ecd_conin = ST->ConIn;
+ cp->c_flags |= C_PRESENTIN | C_PRESENTOUT;
+
+ 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;
+ }
+
+ 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;
- default:
- bail_out(c);
- break;
}
+ 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];
+ snprintf(env, sizeof (env), "%u", (unsigned)rows);
+ setenv("screen-#rows", env, 1);
+ snprintf(env, sizeof (env), "%u", (unsigned)cols);
+ setenv("screen-#cols", env, 1);
+ }
+
+ if (efi_find_framebuffer(&efifb)) {
+ console_mode = EfiConsoleControlScreenText;
+ ecd->ecd_visual_ops = &text_ops;
+ } else {
+ efi_framebuffer_setup();
+ console_mode = EfiConsoleControlScreenGraphics;
+ ecd->ecd_visual_ops = &fb_ops;
+ }
+
+ 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);
-#endif
+ struct efi_console_data *ecd;
+ void *coninex;
+ EFI_STATUS status;
+ int rc;
+
+ conout->SetAttribute(conout, EFI_TEXT_ATTR(DEFAULT_FGCOLOR,
+ DEFAULT_BGCOLOR));
+ memset(keybuf, 0, KEYBUFSZ);
+
+ ecd = cp->c_private;
+ coninex = NULL;
+ /*
+ * Try to set up for SimpleTextInputEx protocol. If not available,
+ * we will use SimpleTextInput protocol.
+ */
+ status = BS->OpenProtocol(ST->ConsoleInHandle, &simple_input_ex_guid,
+ &coninex, IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (status == EFI_SUCCESS)
+ ecd->ecd_coninex = coninex;
+
+ 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);
+}
+
+static void
+efi_cons_putchar(struct console *cp __unused, int c)
+{
+ 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
@@ -560,7 +626,7 @@ keybuf_inschar(EFI_INPUT_KEY *key)
}
static bool
-efi_readkey(void)
+efi_readkey(SIMPLE_INPUT_INTERFACE *conin)
{
EFI_STATUS status;
EFI_INPUT_KEY key;
@@ -573,37 +639,97 @@ efi_readkey(void)
return (false);
}
-int
-efi_cons_getchar(struct console *cp __attribute((unused)))
+static bool
+efi_readkey_ex(EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *coninex)
{
+ 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++;
+ }
+ }
+ }
+
+ keybuf_inschar(kp);
+ return (true);
+ }
+ return (false);
+}
+
+static int
+efi_cons_getchar(struct console *cp)
+{
+ struct efi_console_data *ecd;
int c;
if ((c = keybuf_getchar()) != 0)
return (c);
+ ecd = cp->c_private;
key_pending = 0;
- if (efi_readkey())
- return (keybuf_getchar());
+ if (ecd->ecd_coninex == NULL) {
+ if (efi_readkey(ecd->ecd_conin))
+ return (keybuf_getchar());
+ } else {
+ if (efi_readkey_ex(ecd->ecd_coninex))
+ return (keybuf_getchar());
+ }
return (-1);
}
-int
-efi_cons_poll(struct console *cp __attribute((unused)))
+static int
+efi_cons_poll(struct console *cp)
{
+ struct efi_console_data *ecd;
+ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *coninex;
+ SIMPLE_INPUT_INTERFACE *conin;
+ EFI_STATUS status;
+
if (keybuf_ischar() || key_pending)
return (1);
+ ecd = cp->c_private;
+ coninex = ecd->ecd_coninex;
+ conin = ecd->ecd_conin;
/*
* Some EFI implementation (u-boot for example) do not support
* WaitForKey().
* CheckEvent() can clear the signaled state.
*/
- if (conin->WaitForKey == NULL)
- key_pending = efi_readkey();
- else
- key_pending = BS->CheckEvent(conin->WaitForKey) == EFI_SUCCESS;
+ if (coninex != NULL) {
+ if (coninex->WaitForKeyEx == NULL)
+ key_pending = efi_readkey_ex(coninex);
+ else {
+ status = BS->CheckEvent(coninex->WaitForKeyEx);
+ key_pending = status == EFI_SUCCESS;
+ }
+ } else {
+ if (conin->WaitForKey == NULL)
+ key_pending = efi_readkey(conin);
+ else {
+ status = BS->CheckEvent(conin->WaitForKey);
+ key_pending = status == EFI_SUCCESS;
+ }
+ }
return (key_pending);
}
@@ -613,31 +739,13 @@ 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[0] = c;
buf[1] = 0; /* terminate string */
+ status = conout->TestString(conout, buf);
+ if (EFI_ERROR(status))
+ buf[0] = '?';
conout->OutputString(conout, buf);
}
diff --git a/usr/src/boot/sys/boot/efi/loader/Makefile.com b/usr/src/boot/sys/boot/efi/loader/Makefile.com
index 7674305b5c..74099f45d9 100644
--- a/usr/src/boot/sys/boot/efi/loader/Makefile.com
+++ b/usr/src/boot/sys/boot/efi/loader/Makefile.com
@@ -15,6 +15,7 @@
include $(SRC)/Makefile.master
include $(SRC)/boot/Makefile.version
+include $(SRC)/boot/sys/boot/Makefile.inc
CC= $(GNUC_ROOT)/bin/gcc
LD= $(GNU_ROOT)/bin/gld
@@ -23,35 +24,47 @@ OBJDUMP= $(GNU_ROOT)/bin/gobjdump
PROG= loader.sym
+PNGLITE= $(SRC)/common/pnglite
+
# architecture-specific loader code
-SRCS= acpi.c \
+SRCS= \
+ acpi.c \
autoload.c \
bootinfo.c \
conf.c \
copy.c \
efi_main.c \
+ font.c \
+ $(FONT).c \
framebuffer.c \
+ list.c \
main.c \
memmap.c \
multiboot.S \
multiboot2.c \
self_reloc.c \
smbios.c \
+ tem.c \
vers.c
-OBJS= acpi.o \
+OBJS= \
+ acpi.o \
autoload.o \
bootinfo.o \
conf.o \
copy.o \
efi_main.o \
+ font.o \
+ $(FONT).o \
framebuffer.o \
+ list.o \
main.o \
memmap.o \
multiboot.o \
multiboot2.o \
self_reloc.o \
smbios.o \
+ tem.o \
vers.o
CFLAGS= -Os
@@ -71,8 +84,8 @@ CPPFLAGS += -I../../../i386/libi386
CPPFLAGS += -I../../../zfs
CPPFLAGS += -I../../../../cddl/boot/zfs
CPPFLAGS += -I$(SRC)/uts/intel/sys/acpi
-CPPFLAGS += -DEFI_ZFS_BOOT
-CPPFLAGS += -DNO_PCI -DEFI -DTERM_EMU
+CPPFLAGS += -I$(PNGLITE)
+CPPFLAGS += -DNO_PCI -DEFI
# Export serial numbers, UUID, and asset tag from loader.
smbios.o := CPPFLAGS += -DSMBIOS_SERIAL_NUMBERS
@@ -109,7 +122,8 @@ LDFLAGS = -nostdlib --eh-frame-hdr
LDFLAGS += -shared --hash-style=both --enable-new-dtags
LDFLAGS += -T$(LDSCRIPT) -Bsymbolic
-CLEANFILES= loader.sym loader.bin vers.c
+CLEANFILES= loader.sym loader.bin
+CLEANFILES += $(FONT).c vers.c
NEWVERSWHAT= "EFI loader" $(MACHINE)
@@ -180,8 +194,11 @@ clean clobber:
%.o: $(SRC)/common/list/%.c
$(COMPILE.c) -DNDEBUG $<
-%.o: $(SRC)/uts/common/io/font/%.c
+%.o: $(SRC)/common/font/%.c
$(COMPILE.c) $<
+$(FONT).c: $(FONT_DIR)/$(FONT_SRC)
+ $(VTFONTCVT) -f compressed-source -o $@ $(FONT_DIR)/$(FONT_SRC)
+
$(ROOT_BOOT)/%: %
$(INS.file)
diff --git a/usr/src/boot/sys/boot/efi/loader/comconsole.c b/usr/src/boot/sys/boot/efi/loader/comconsole.c
index 8bcce95e0b..c46971eeda 100644
--- a/usr/src/boot/sys/boot/efi/loader/comconsole.c
+++ b/usr/src/boot/sys/boot/efi/loader/comconsole.c
@@ -58,6 +58,7 @@ static int comc_init(struct console *, int);
static void comc_putchar(struct console *, int);
static int comc_getchar(struct console *);
static int comc_ischar(struct console *);
+static int comc_ioctl(struct console *, int, void *);
static void comc_setup(struct console *);
static char *comc_asprint_mode(struct serial *);
static int comc_parse_mode(struct serial *, const char *);
@@ -74,6 +75,7 @@ struct console ttya = {
.c_out = comc_putchar,
.c_in = comc_getchar,
.c_ready = comc_ischar,
+ .c_ioctl = comc_ioctl,
.c_private = NULL
};
@@ -86,6 +88,7 @@ struct console ttyb = {
.c_out = comc_putchar,
.c_in = comc_getchar,
.c_ready = comc_ischar,
+ .c_ioctl = comc_ioctl,
.c_private = NULL
};
@@ -98,6 +101,7 @@ struct console ttyc = {
.c_out = comc_putchar,
.c_in = comc_getchar,
.c_ready = comc_ischar,
+ .c_ioctl = comc_ioctl,
.c_private = NULL
};
@@ -110,6 +114,7 @@ struct console ttyd = {
.c_out = comc_putchar,
.c_in = comc_getchar,
.c_ready = comc_ischar,
+ .c_ioctl = comc_ioctl,
.c_private = NULL
};
@@ -307,6 +312,12 @@ comc_ischar(struct console *cp)
return (!(control & EFI_SERIAL_INPUT_BUFFER_EMPTY));
}
+static int
+comc_ioctl(struct console *cp __unused, int cmd __unused, void *data __unused)
+{
+ return (ENOTTY);
+}
+
static char *
comc_asprint_mode(struct serial *sp)
{
diff --git a/usr/src/boot/sys/boot/efi/loader/efi_main.c b/usr/src/boot/sys/boot/efi/loader/efi_main.c
index 86917da147..c65be09057 100644
--- a/usr/src/boot/sys/boot/efi/loader/efi_main.c
+++ b/usr/src/boot/sys/boot/efi/loader/efi_main.c
@@ -27,7 +27,6 @@
#include <sys/cdefs.h>
#include <efi.h>
-#include <eficonsctl.h>
#include <efilib.h>
#include <stand.h>
@@ -71,14 +70,9 @@ EFI_STATUS
efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table)
{
static EFI_GUID image_protocol = LOADED_IMAGE_PROTOCOL;
- static EFI_GUID console_control_protocol =
- EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
- EFI_CONSOLE_CONTROL_PROTOCOL *console_control = NULL;
EFI_LOADED_IMAGE *img;
CHAR16 *argp, *args, **argv;
EFI_STATUS status;
- SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
- UINTN i, max_dim, best_mode, cols, rows;
int argc, addprog;
IH = image_handle;
@@ -86,26 +80,6 @@ efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table)
BS = ST->BootServices;
RS = ST->RuntimeServices;
- status = BS->LocateProtocol(&console_control_protocol, NULL,
- (VOID **)&console_control);
- if (status == EFI_SUCCESS)
- (void)console_control->SetMode(console_control,
- EfiConsoleControlScreenText);
-
- conout = ST->ConOut;
- 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;
- }
- }
- if (max_dim > 0)
- conout->SetMode(conout, best_mode);
-
heapsize = 64 * 1024 * 1024;
/* 4GB upper limit, try to leave some space from 1MB */
heap = 0x0000000100000000;
@@ -116,18 +90,6 @@ efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table)
setheap((void *)(uintptr_t)heap, (void *)(uintptr_t)(heap + heapsize));
- status = conout->QueryMode(conout, best_mode, &cols, &rows);
- if (EFI_ERROR(status)) {
- setenv("LINES", "24", 1);
- setenv("COLUMNS", "80", 1);
- } else {
- char buf[8];
- snprintf(buf, sizeof (buf), "%u", (unsigned)rows);
- setenv("LINES", buf, 1);
- snprintf(buf, sizeof (buf), "%u", (unsigned)cols);
- setenv("COLUMNS", buf, 1);
- }
-
/* Use efi_exit() from here on... */
status = BS->HandleProtocol(IH, &image_protocol, (VOID**)&img);
diff --git a/usr/src/boot/sys/boot/efi/loader/framebuffer.c b/usr/src/boot/sys/boot/efi/loader/framebuffer.c
index 77d01dfb64..9428c8dba9 100644
--- a/usr/src/boot/sys/boot/efi/loader/framebuffer.c
+++ b/usr/src/boot/sys/boot/efi/loader/framebuffer.c
@@ -31,24 +31,36 @@
#include <stand.h>
#include <bootstrap.h>
#include <sys/endian.h>
+#include <sys/consplat.h>
#include <efi.h>
#include <efilib.h>
#include <efiuga.h>
#include <efipciio.h>
+#include <Protocol/EdidActive.h>
+#include <Protocol/EdidDiscovered.h>
#include <machine/metadata.h>
+#include "gfx_fb.h"
#include "framebuffer.h"
static EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
static EFI_GUID pciio_guid = EFI_PCI_IO_PROTOCOL_GUID;
static EFI_GUID uga_guid = EFI_UGA_DRAW_PROTOCOL_GUID;
+static EFI_GUID active_edid_guid = EFI_EDID_ACTIVE_PROTOCOL_GUID;
+static EFI_GUID discovered_edid_guid = EFI_EDID_DISCOVERED_PROTOCOL_GUID;
-static u_int
+/* Saved initial GOP mode. */
+static uint32_t default_mode = (uint32_t)-1;
+
+static uint32_t gop_default_mode(void);
+static int efifb_set_mode(EFI_GRAPHICS_OUTPUT *, u_int);
+
+static uint_t
efifb_color_depth(struct efi_fb *efifb)
{
uint32_t mask;
- u_int depth;
+ uint_t depth;
mask = efifb->fb_mask_red | efifb->fb_mask_green |
efifb->fb_mask_blue | efifb->fb_mask_reserved;
@@ -105,6 +117,8 @@ efifb_from_gop(struct efi_fb *efifb, EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *mode,
efifb->fb_stride = info->PixelsPerScanLine;
result = efifb_mask_from_pixfmt(efifb, info->PixelFormat,
&info->PixelInformation);
+ if (efifb->fb_addr == 0)
+ result = 1;
return (result);
}
@@ -421,19 +435,109 @@ efifb_from_uga(struct efi_fb *efifb, EFI_UGA_DRAW_PROTOCOL *uga)
* frame buffer.
*/
efifb->fb_size = efifb->fb_height * efifb->fb_stride * 4;
+ if (efifb->fb_addr == 0)
+ return (1);
return (0);
}
+/*
+ * Fetch EDID info. Caller must free the buffer.
+ */
+static struct vesa_edid_info *
+efifb_gop_get_edid(EFI_HANDLE gop)
+{
+ const uint8_t magic[] = EDID_MAGIC;
+ EFI_EDID_ACTIVE_PROTOCOL *edid;
+ struct vesa_edid_info *edid_info;
+ EFI_GUID *guid;
+ EFI_STATUS status;
+ size_t size;
+
+ edid_info = calloc(1, sizeof (*edid_info));
+ if (edid_info == NULL)
+ return (NULL);
+
+ guid = &active_edid_guid;
+ status = BS->OpenProtocol(gop, guid, (VOID **)&edid, IH, NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (status != EFI_SUCCESS) {
+ guid = &discovered_edid_guid;
+ status = BS->OpenProtocol(gop, guid, (VOID **)&edid, IH, NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ }
+ if (status != EFI_SUCCESS)
+ goto error;
+
+ size = edid->SizeOfEdid;
+ if (size > sizeof (*edid_info))
+ size = sizeof (*edid_info);
+
+ memcpy(edid_info, edid->Edid, size);
+ status = BS->CloseProtocol(gop, guid, IH, NULL);
+
+ /* Validate EDID */
+ if (memcmp(edid_info, magic, sizeof(magic)) != 0)
+ goto error;
+
+ if (edid_info->header.version == 1 &&
+ (edid_info->display.supported_features
+ & EDID_FEATURE_PREFERRED_TIMING_MODE) &&
+ edid_info->detailed_timings[0].pixel_clock) {
+ return (edid_info);
+ }
+
+error:
+ free(edid_info);
+ return (NULL);
+}
+
+static int
+efifb_get_edid(UINT32 *pwidth, UINT32 *pheight)
+{
+ extern EFI_GRAPHICS_OUTPUT *gop;
+ struct vesa_edid_info *edid_info;
+ struct edid_detailed_timings *timings;
+ int rv = 1;
+
+ edid_info = efifb_gop_get_edid(gop);
+ if (edid_info != NULL) {
+ timings = edid_info->detailed_timings;
+ *pwidth = timings[0].horizontal_active_lo |
+ (((int)(timings[0].horizontal_hi & 0xf0)) << 4);
+
+ *pheight = timings[0].vertical_active_lo |
+ (((int)(timings[0].vertical_hi & 0xf0)) << 4);
+ rv = 0;
+ }
+ free(edid_info);
+ return (rv);
+}
+
int
efi_find_framebuffer(struct efi_fb *efifb)
{
- EFI_GRAPHICS_OUTPUT *gop;
- EFI_UGA_DRAW_PROTOCOL *uga;
+ extern EFI_GRAPHICS_OUTPUT *gop;
+ extern EFI_UGA_DRAW_PROTOCOL *uga;
EFI_STATUS status;
+ uint32_t mode;
+
+ if (gop != NULL)
+ return (efifb_from_gop(efifb, gop->Mode, gop->Mode->Info));
status = BS->LocateProtocol(&gop_guid, NULL, (VOID **)&gop);
- if (status == EFI_SUCCESS)
+ if (status == EFI_SUCCESS) {
+ /* Save default mode. */
+ if (default_mode == (uint32_t)-1) {
+ default_mode = gop->Mode->Mode;
+ }
+ mode = gop_default_mode();
+ if (mode != gop->Mode->Mode)
+ efifb_set_mode(gop, mode);
return (efifb_from_gop(efifb, gop->Mode, gop->Mode->Info));
+ }
+
+ if (uga != NULL)
+ return (efifb_from_uga(efifb, uga));
status = BS->LocateProtocol(&uga_guid, NULL, (VOID **)&uga);
if (status == EFI_SUCCESS)
@@ -445,89 +549,264 @@ efi_find_framebuffer(struct efi_fb *efifb)
static void
print_efifb(int mode, struct efi_fb *efifb, int verbose)
{
- u_int depth;
+ uint_t depth;
+ UINT32 width, height;
+
+ if (verbose == 1) {
+ printf("Framebuffer mode: %s\n",
+ plat_stdout_is_framebuffer() ? "on" : "off");
+ if (efifb_get_edid(&width, &height) == 0)
+ printf("EDID mode: %dx%d\n\n", width, height);
+ }
- if (mode >= 0)
+ if (mode >= 0) {
+ if (verbose == 1)
+ printf("GOP ");
printf("mode %d: ", mode);
+ }
depth = efifb_color_depth(efifb);
- printf("%ux%ux%u, stride=%u", efifb->fb_width, efifb->fb_height,
- depth, efifb->fb_stride);
+ printf("%ux%ux%u", efifb->fb_width, efifb->fb_height, depth);
+ if (verbose)
+ printf(", stride=%u", efifb->fb_stride);
if (verbose) {
printf("\n frame buffer: address=%jx, size=%jx",
(uintmax_t)efifb->fb_addr, (uintmax_t)efifb->fb_size);
printf("\n color mask: R=%08x, G=%08x, B=%08x\n",
efifb->fb_mask_red, efifb->fb_mask_green,
efifb->fb_mask_blue);
+ if (efifb->fb_addr == 0) {
+ printf("Warning: this mode is not implementing the "
+ "linear framebuffer. The illumos\n\tconsole is "
+ "not available with this mode and will default to "
+ "ttya\n");
+ }
}
}
-COMMAND_SET(gop, "gop", "graphics output protocol", command_gop);
+static int
+efifb_set_mode(EFI_GRAPHICS_OUTPUT *gop, u_int mode)
+{
+ EFI_STATUS status;
+
+ status = gop->SetMode(gop, mode);
+ if (EFI_ERROR(status)) {
+ snprintf(command_errbuf, sizeof (command_errbuf),
+ "Unable to set mode to %u (error=%lu)",
+ mode, EFI_ERROR_CODE(status));
+ return (CMD_ERROR);
+ }
+ return (CMD_OK);
+}
+
+/*
+ * Verify existance of mode number or find mode by
+ * dimensions. If depth is not given, walk values 32, 24, 16, 8.
+ * Return MaxMode if mode is not found.
+ */
+static int
+efifb_find_mode_xydm(UINT32 x, UINT32 y, int depth, int m)
+{
+ extern EFI_GRAPHICS_OUTPUT *gop;
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info;
+ EFI_STATUS status;
+ UINTN infosz;
+ struct efi_fb fb;
+ UINT32 mode;
+ uint_t d, i;
+
+ if (m != -1)
+ i = 8;
+ else if (depth == -1)
+ i = 32;
+ else
+ i = depth;
+
+ while (i > 0) {
+ for (mode = 0; mode < gop->Mode->MaxMode; mode++) {
+ status = gop->QueryMode(gop, mode, &infosz, &info);
+ if (EFI_ERROR(status))
+ continue;
+
+ if (m != -1) {
+ if ((UINT32)m == mode)
+ return (mode);
+ else
+ continue;
+ }
+
+ efifb_from_gop(&fb, gop->Mode, info);
+ d = efifb_color_depth(&fb);
+ if (x == fb.fb_width && y == fb.fb_height && d == i)
+ return (mode);
+ }
+
+ if (depth != -1)
+ break;
+
+ i -= 8;
+ }
+
+ return (gop->Mode->MaxMode);
+}
+
+static int
+efifb_find_mode(char *str)
+{
+ extern EFI_GRAPHICS_OUTPUT *gop;
+ int x, y, depth;
+
+ if (!gfx_parse_mode_str(str, &x, &y, &depth))
+ return (gop->Mode->MaxMode);
+
+ return (efifb_find_mode_xydm(x, y, depth, -1));
+}
+
+/*
+ * gop_default_mode(). Try to set mode based on EDID.
+ */
+static uint32_t
+gop_default_mode(void)
+{
+ extern EFI_GRAPHICS_OUTPUT *gop;
+ UINT32 mode, width = 0, height = 0;
+
+ mode = gop->Mode->MaxMode;
+ if (efifb_get_edid(&width, &height) == 0)
+ mode = efifb_find_mode_xydm(width, height, -1, -1);
+
+ if (mode == gop->Mode->MaxMode)
+ mode = default_mode;
+
+ return (mode);
+}
+
+COMMAND_SET(framebuffer, "framebuffer", "framebuffer mode management",
+ command_gop);
static int
command_gop(int argc, char *argv[])
{
- struct efi_fb efifb;
- EFI_GRAPHICS_OUTPUT *gop;
+ extern struct efi_fb efifb;
+ extern EFI_GRAPHICS_OUTPUT *gop;
+ struct efi_fb fb;
EFI_STATUS status;
+ char *arg, *cp;
u_int mode;
- status = BS->LocateProtocol(&gop_guid, NULL, (VOID **)&gop);
- if (EFI_ERROR(status)) {
+ if (gop == NULL) {
snprintf(command_errbuf, sizeof (command_errbuf),
- "%s: Graphics Output Protocol not present (error=%lu)",
- argv[0], EFI_ERROR_CODE(status));
+ "%s: Graphics Output Protocol not present", argv[0]);
return (CMD_ERROR);
}
if (argc < 2)
goto usage;
+ /*
+ * Note we can not turn the GOP itself off, but instead we instruct
+ * tem to use text mode.
+ */
+ if (strcmp(argv[1], "off") == 0) {
+ if (argc != 2)
+ goto usage;
+
+ plat_cons_update_mode(EfiConsoleControlScreenText);
+ return (CMD_OK);
+ }
+
+ /*
+ * Set GOP to use default mode, then notify tem.
+ */
+ if (strcmp(argv[1], "on") == 0) {
+ if (argc != 2)
+ goto usage;
+
+ mode = gop_default_mode();
+ if (mode != gop->Mode->Mode)
+ efifb_set_mode(gop, mode);
+
+ plat_cons_update_mode(EfiConsoleControlScreenGraphics);
+ return (CMD_OK);
+ }
+
if (!strcmp(argv[1], "set")) {
- char *cp;
+ int rv;
if (argc != 3)
goto usage;
- mode = strtol(argv[2], &cp, 0);
- if (cp[0] != '\0') {
- sprintf(command_errbuf, "mode is an integer");
- return (CMD_ERROR);
- }
- status = gop->SetMode(gop, mode);
- if (EFI_ERROR(status)) {
- snprintf(command_errbuf, sizeof (command_errbuf),
- "%s: Unable to set mode to %u (error=%lu)",
- argv[0], mode, EFI_ERROR_CODE(status));
- return (CMD_ERROR);
+
+ arg = argv[2];
+ if (strchr(arg, 'x') == NULL) {
+ errno = 0;
+ mode = strtoul(arg, &cp, 0);
+ if (errno != 0 || *arg == '\0' || cp[0] != '\0') {
+ snprintf(command_errbuf,
+ sizeof (command_errbuf),
+ "mode should be an integer");
+ return (CMD_ERROR);
+ }
+ mode = efifb_find_mode_xydm(0, 0, 0, mode);
+ } else {
+ mode = efifb_find_mode(arg);
}
- } else if (!strcmp(argv[1], "get")) {
+
+ if (mode == gop->Mode->MaxMode)
+ mode = gop->Mode->Mode;
+
+ rv = efifb_set_mode(gop, mode);
+ plat_cons_update_mode(EfiConsoleControlScreenGraphics);
+ return (rv);
+ }
+
+ if (!strcmp(argv[1], "get")) {
if (argc != 2)
goto usage;
- efifb_from_gop(&efifb, gop->Mode, gop->Mode->Info);
+
print_efifb(gop->Mode->Mode, &efifb, 1);
printf("\n");
- } else if (!strcmp(argv[1], "list")) {
+ return (CMD_OK);
+ }
+
+ if (!strcmp(argv[1], "list")) {
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info;
UINTN infosz;
+ int depth, d = -1;
- if (argc != 2)
+ if (argc != 2 && argc != 3)
goto usage;
+
+ if (argc == 3) {
+ arg = argv[2];
+ errno = 0;
+ d = strtoul(arg, &cp, 0);
+ if (errno != 0 || *arg == '\0' || cp[0] != '\0') {
+ snprintf(command_errbuf,
+ sizeof (command_errbuf),
+ "depth should be an integer");
+ return (CMD_ERROR);
+ }
+ }
pager_open();
for (mode = 0; mode < gop->Mode->MaxMode; mode++) {
status = gop->QueryMode(gop, mode, &infosz, &info);
if (EFI_ERROR(status))
continue;
- efifb_from_gop(&efifb, gop->Mode, info);
- print_efifb(mode, &efifb, 0);
+ efifb_from_gop(&fb, gop->Mode, info);
+ depth = efifb_color_depth(&fb);
+ if (d != -1 && d != depth)
+ continue;
+ print_efifb(mode, &fb, 0);
if (pager_output("\n"))
break;
}
pager_close();
+ return (CMD_OK);
}
- return (CMD_OK);
- usage:
+usage:
snprintf(command_errbuf, sizeof (command_errbuf),
- "usage: %s [list | get | set <mode>]", argv[0]);
+ "usage: %s on | off | get | list [depth] | "
+ "set <display or GOP mode number>", argv[0]);
return (CMD_ERROR);
}
@@ -536,22 +815,19 @@ COMMAND_SET(uga, "uga", "universal graphics adapter", command_uga);
static int
command_uga(int argc, char *argv[])
{
- struct efi_fb efifb;
- EFI_UGA_DRAW_PROTOCOL *uga;
- EFI_STATUS status;
+ extern struct efi_fb efifb;
+ extern EFI_UGA_DRAW_PROTOCOL *uga;
- status = BS->LocateProtocol(&uga_guid, NULL, (VOID **)&uga);
- if (EFI_ERROR(status)) {
+ if (uga == NULL) {
snprintf(command_errbuf, sizeof (command_errbuf),
- "%s: UGA Protocol not present (error=%lu)",
- argv[0], EFI_ERROR_CODE(status));
+ "%s: UGA Protocol not present", argv[0]);
return (CMD_ERROR);
}
if (argc != 1)
goto usage;
- if (efifb_from_uga(&efifb, uga) != CMD_OK) {
+ if (efifb.fb_addr == 0) {
snprintf(command_errbuf, sizeof (command_errbuf),
"%s: Unable to get UGA information", argv[0]);
return (CMD_ERROR);
diff --git a/usr/src/boot/sys/boot/efi/loader/main.c b/usr/src/boot/sys/boot/efi/loader/main.c
index dabde127b1..0f5ff21018 100644
--- a/usr/src/boot/sys/boot/efi/loader/main.c
+++ b/usr/src/boot/sys/boot/efi/loader/main.c
@@ -31,6 +31,7 @@
#include <sys/param.h>
#include <sys/reboot.h>
#include <sys/boot.h>
+#include <sys/consplat.h>
#include <stand.h>
#include <inttypes.h>
#include <string.h>
@@ -44,6 +45,7 @@
#include <uuid.h>
#include <bootstrap.h>
+#include <gfx_fb.h>
#include <smbios.h>
#include <libzfs.h>
@@ -682,6 +684,7 @@ main(int argc, CHAR16 *argv[])
if (!interactive_interrupt("Failed to find bootable partition"))
return (EFI_NOT_FOUND);
+ autoload_font(); /* Set up the font list for console. */
efi_init_environment();
setenv("ISADIR", "amd64", 1); /* we only build 64bit */
bi_isadir(); /* set ISADIR */
@@ -846,10 +849,14 @@ command_mode(int argc, char *argv[])
unsigned int mode;
int i;
char *cp;
- char rowenv[8];
EFI_STATUS status;
SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
- extern void HO(void);
+ EFI_CONSOLE_CONTROL_SCREEN_MODE sm;
+
+ if (plat_stdout_is_framebuffer())
+ sm = EfiConsoleControlScreenGraphics;
+ else
+ sm = EfiConsoleControlScreenText;
conout = ST->ConOut;
@@ -869,11 +876,7 @@ command_mode(int argc, char *argv[])
printf("couldn't set mode %d\n", mode);
return (CMD_ERROR);
}
- sprintf(rowenv, "%u", (unsigned)rows);
- setenv("LINES", rowenv, 1);
- sprintf(rowenv, "%u", (unsigned)cols);
- setenv("COLUMNS", rowenv, 1);
- HO(); /* set cursor */
+ plat_cons_update_mode(sm);
return (CMD_OK);
}
diff --git a/usr/src/boot/sys/boot/forth/Makefile.inc b/usr/src/boot/sys/boot/forth/Makefile.inc
index 43c109a6da..eb2576bd64 100644
--- a/usr/src/boot/sys/boot/forth/Makefile.inc
+++ b/usr/src/boot/sys/boot/forth/Makefile.inc
@@ -24,3 +24,4 @@ FORTH += screen.4th
FORTH += shortcuts.4th
FORTH += support.4th
FORTH += version.4th
+FILES += illumos.png
diff --git a/usr/src/boot/sys/boot/forth/frames.4th b/usr/src/boot/sys/boot/forth/frames.4th
index db42f72d0b..a1d170f0e9 100644
--- a/usr/src/boot/sys/boot/forth/frames.4th
+++ b/usr/src/boot/sys/boot/forth/frames.4th
@@ -1,7 +1,7 @@
\ Copyright (c) 2003 Scott Long <scottl@FreeBSD.org>
\ Copyright (c) 2012-2015 Devin Teske <dteske@FreeBSD.org>
\ All rights reserved.
-\
+\
\ Redistribution and use in source and binary forms, with or without
\ modification, are permitted provided that the following conditions
\ are met:
@@ -10,7 +10,7 @@
\ 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
@@ -22,7 +22,7 @@
\ 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.
-\
+\
marker task-frames.4th
@@ -46,32 +46,32 @@ variable fill
43 constant ascii_plus
\ Single frames
-196 constant sh_el
-179 constant sv_el
-218 constant slt_el
-192 constant slb_el
-191 constant srt_el
-217 constant srb_el
+$2500 constant sh_el
+$2502 constant sv_el
+$250c constant slt_el
+$2514 constant slb_el
+$2510 constant srt_el
+$2518 constant srb_el
\ Double frames
-205 constant dh_el
-186 constant dv_el
-201 constant dlt_el
-200 constant dlb_el
-187 constant drt_el
-188 constant drb_el
+$2550 constant dh_el
+$2551 constant dv_el
+$2554 constant dlt_el
+$255a constant dlb_el
+$2557 constant drt_el
+$255d constant drb_el
\ Fillings
0 constant fill_none
32 constant fill_blank
-176 constant fill_dark
-177 constant fill_med
-178 constant fill_bright
+$2591 constant fill_dark
+$2592 constant fill_med
+$2593 constant fill_bright
only forth definitions also frame-drawing
: hline ( len x y -- ) \ Draw horizontal single line
at-xy \ move cursor
0 do
- h_el @ emit
+ h_el @ xemit
loop
;
@@ -112,7 +112,7 @@ only forth definitions also frame-drawing
2dup 4 pick
0 do
at-xy
- v_el @ emit
+ v_el @ xemit
1+
2dup
loop
@@ -120,6 +120,19 @@ only forth definitions also frame-drawing
;
: box ( w h x y -- ) \ Draw a box
+ \ Do we have frame buffer?
+ s" screen-height" getenv
+ dup -1 <> if
+ 2drop
+ rot ( w x y h )
+ over + >R ( w x y -- R: y+h )
+ swap rot ( y x w -- R: y+h )
+ over + >R ( y x -- R: y+h x+w )
+ swap R> R> term-drawrect
+ exit
+ else
+ drop
+ then
2dup 1+ 4 pick 1- -rot
vline \ Draw left vert line
2dup 1+ swap 5 pick + swap 4 pick 1- -rot
@@ -128,10 +141,10 @@ only forth definitions also frame-drawing
hline \ Draw top horiz line
2dup swap 1+ swap 4 pick + 5 pick 1- -rot
hline \ Draw bottom horiz line
- 2dup at-xy lt_el @ emit \ Draw left-top corner
- 2dup 4 pick + at-xy lb_el @ emit \ Draw left bottom corner
- 2dup swap 5 pick + swap at-xy rt_el @ emit \ Draw right top corner
- 2 pick + swap 3 pick + swap at-xy rb_el @ emit
+ 2dup at-xy lt_el @ xemit \ Draw left-top corner
+ 2dup 4 pick + at-xy lb_el @ xemit \ Draw left bottom corner
+ 2dup swap 5 pick + swap at-xy rt_el @ xemit \ Draw right top corner
+ 2 pick + swap 3 pick + swap at-xy rb_el @ xemit
2drop
;
diff --git a/usr/src/boot/sys/boot/forth/illumos.png b/usr/src/boot/sys/boot/forth/illumos.png
new file mode 100644
index 0000000000..3af7a2f360
--- /dev/null
+++ b/usr/src/boot/sys/boot/forth/illumos.png
Binary files differ
diff --git a/usr/src/boot/sys/boot/forth/logo-illumos.4th b/usr/src/boot/sys/boot/forth/logo-illumos.4th
index 77b28a683b..a527198094 100644
--- a/usr/src/boot/sys/boot/forth/logo-illumos.4th
+++ b/usr/src/boot/sys/boot/forth/logo-illumos.4th
@@ -2,7 +2,7 @@
\ Copyright (c) 2003 Aleksander Fafula <alex@fafula.com>
\ Copyright (c) 2006-2015 Devin Teske <dteske@FreeBSD.org>
\ All rights reserved.
-\
+\
\ Redistribution and use in source and binary forms, with or without
\ modification, are permitted provided that the following conditions
\ are met:
@@ -11,7 +11,7 @@
\ 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
@@ -23,8 +23,7 @@
\ 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.
-\
-\ $FreeBSD$
+\
46 logoX ! 4 logoY ! \ Initialize logo placement defaults
@@ -37,6 +36,8 @@
: logo ( x y -- ) \ color Illumos logo
+ s" /boot/illumos.png" fb-putimage if 2drop exit then
+
s" @[33m, " logo+
s" @[33m,./% @[31m& " logo+
s" @[33m(****@[31m*( " logo+
diff --git a/usr/src/boot/sys/boot/i386/gptzfsboot/zfsboot.c b/usr/src/boot/sys/boot/i386/gptzfsboot/zfsboot.c
index 4238afe3e8..5d57d909ce 100644
--- a/usr/src/boot/sys/boot/i386/gptzfsboot/zfsboot.c
+++ b/usr/src/boot/sys/boot/i386/gptzfsboot/zfsboot.c
@@ -196,7 +196,7 @@ main(void)
env_nounset);
/* Process configuration file */
- setenv("LINES", "24", 1);
+ setenv("screen-#rows", "24", 1);
auto_boot = 1;
fd = open(PATH_CONFIG, O_RDONLY);
diff --git a/usr/src/boot/sys/boot/i386/libi386/Makefile b/usr/src/boot/sys/boot/i386/libi386/Makefile
index b2d8cca9ef..a5c52f2703 100644
--- a/usr/src/boot/sys/boot/i386/libi386/Makefile
+++ b/usr/src/boot/sys/boot/i386/libi386/Makefile
@@ -42,14 +42,21 @@ SRCS= biosacpi.c biosdisk.c biosmem.c biospnp.c \
elf64_freebsd.c multiboot.c multiboot_tramp.S \
i386_copy.c i386_module.c nullconsole.c pxe.c pxetramp.s \
smbios.c time.c vidconsole.c amd64_tramp.S spinconsole.c linux.c \
- relocater_tramp.S
+ relocater_tramp.S vgasubr.c vbe.c
OBJS= biosacpi.o biosdisk.o biosmem.o biospnp.o \
biospci.o biossmap.o bootinfo.o bootinfo32.o bootinfo64.o \
comconsole.o cpuid.o devicename.o elf32_freebsd.o \
elf64_freebsd.o multiboot.o multiboot_tramp.o \
i386_copy.o i386_module.o nullconsole.o pxe.o pxetramp.o \
smbios.o time.o vidconsole.o amd64_tramp.o spinconsole.o linux.o \
- relocater_tramp.o
+ relocater_tramp.o vgasubr.o vbe.o
+
+COMMON= ../../common
+PNGLITE=$(SRC)/common/pnglite
+VGASUBR=$(SRC)/common/vga
+CPPFLAGS += -I$(PNGLITE)
+SRCS += $(COMMON)/gfx_fb.c $(PNGLITE)/pnglite.c
+OBJS += gfx_fb.o pnglite.o
LIBZFS= ../../zfs
SRCS += $(LIBZFS)/devicename_stubs.c
@@ -71,9 +78,6 @@ smbios.o := CFLAGS += -DSMBIOS_LITTLE_ENDIAN_UUID
# Use network-endian UUID format for backward compatibility.
#CFLAGS += -DSMBIOS_NETWORK_ENDIAN_UUID
-# Include simple terminal emulation (cons25-compatible)
-CFLAGS += -DTERM_EMU
-
# XXX: make alloca() useable
CFLAGS += -Dalloca=__builtin_alloca
@@ -116,3 +120,12 @@ libi386.a: $(OBJS)
%.o: $(LIBZFS)/%.c
$(COMPILE.c) -o $@ $<
+
+%.o: $(COMMON)/%.c
+ $(COMPILE.c) -o $@ $<
+
+%.o: $(PNGLITE)/%.c
+ $(COMPILE.c) -o $@ $<
+
+%.o: $(VGASUBR)/%.c
+ $(COMPILE.c) -o $@ $<
diff --git a/usr/src/boot/sys/boot/i386/libi386/comconsole.c b/usr/src/boot/sys/boot/i386/libi386/comconsole.c
index a3d3e03f53..29ed725b89 100644
--- a/usr/src/boot/sys/boot/i386/libi386/comconsole.c
+++ b/usr/src/boot/sys/boot/i386/libi386/comconsole.c
@@ -73,6 +73,7 @@ static void comc_putchar(struct console *, int);
static int comc_getchar(struct console *);
static int comc_getspeed(struct serial *);
static int comc_ischar(struct console *);
+static int comc_ioctl(struct console *, int, void *);
static uint32_t comc_parse_pcidev(const char *);
static int comc_pcidev_set(struct env_var *, int, const void *);
static int comc_pcidev_handle(struct console *, uint32_t);
@@ -92,6 +93,7 @@ struct console ttya = {
.c_out = comc_putchar,
.c_in = comc_getchar,
.c_ready = comc_ischar,
+ .c_ioctl = comc_ioctl,
.c_private = NULL
};
@@ -104,6 +106,7 @@ struct console ttyb = {
.c_out = comc_putchar,
.c_in = comc_getchar,
.c_ready = comc_ischar,
+ .c_ioctl = comc_ioctl,
.c_private = NULL
};
@@ -116,6 +119,7 @@ struct console ttyc = {
.c_out = comc_putchar,
.c_in = comc_getchar,
.c_ready = comc_ischar,
+ .c_ioctl = comc_ioctl,
.c_private = NULL
};
@@ -128,6 +132,7 @@ struct console ttyd = {
.c_out = comc_putchar,
.c_in = comc_getchar,
.c_ready = comc_ischar,
+ .c_ioctl = comc_ioctl,
.c_private = NULL
};
@@ -262,6 +267,12 @@ comc_ischar(struct console *cp)
return (inb(sp->ioaddr + com_lsr) & LSR_RXRDY);
}
+static int
+comc_ioctl(struct console *cp __unused, int cmd __unused, void *data __unused)
+{
+ return (ENOTTY);
+}
+
static char *
comc_asprint_mode(struct serial *sp)
{
diff --git a/usr/src/boot/sys/boot/i386/libi386/linux.c b/usr/src/boot/sys/boot/i386/libi386/linux.c
index d69ac26a4e..685e1a1efc 100644
--- a/usr/src/boot/sys/boot/i386/libi386/linux.c
+++ b/usr/src/boot/sys/boot/i386/libi386/linux.c
@@ -27,6 +27,7 @@
#include "linux.h"
#include "bootstrap.h"
+#include "vbe.h"
#include "libi386.h"
#include "btxv86.h"
@@ -395,6 +396,8 @@ linux_exec(struct preloaded_file *fp)
relocator_a20_enabled = 1;
i386_copyin(relocater, 0x600, relocater_size);
+ /* Set VGA text mode */
+ bios_set_text_mode(3);
dev_cleanup();
__exec((void *)0x600);
diff --git a/usr/src/boot/sys/boot/i386/libi386/multiboot.c b/usr/src/boot/sys/boot/i386/libi386/multiboot.c
index 6ee6efc430..836b4907a5 100644
--- a/usr/src/boot/sys/boot/i386/libi386/multiboot.c
+++ b/usr/src/boot/sys/boot/i386/libi386/multiboot.c
@@ -50,6 +50,7 @@
#include "bootstrap.h"
#include <sys/multiboot.h>
+#include "vbe.h"
#include "libzfs.h"
#include "libi386.h"
#include "../btx/lib/btxv86.h"
@@ -429,6 +430,9 @@ multiboot_exec(struct preloaded_file *fp)
free(cmdline);
cmdline = NULL;
+ /* make sure we have text mode */
+ bios_set_text_mode(VGA_TEXT_MODE);
+
dev_cleanup();
__exec((void *)VTOP(multiboot_tramp), MULTIBOOT_BOOTLOADER_MAGIC,
(void *)entry, (void *)VTOP(mb_info));
diff --git a/usr/src/boot/sys/boot/i386/libi386/nullconsole.c b/usr/src/boot/sys/boot/i386/libi386/nullconsole.c
index bef9841ffd..8411d7d8d3 100644
--- a/usr/src/boot/sys/boot/i386/libi386/nullconsole.c
+++ b/usr/src/boot/sys/boot/i386/libi386/nullconsole.c
@@ -1,10 +1,10 @@
-/*-
+/*
* nullconsole.c
*
* Author: Doug Ambrisko <ambrisko@whistle.com>
* Copyright (c) 2000 Whistle Communications, Inc.
* All rights reserved.
- *
+ *
* Subject to the following obligations and disclaimer of warranty, use and
* redistribution of this software, in source or object code forms, with or
* without modifications are expressly permitted by Whistle Communications;
@@ -15,7 +15,7 @@
* Communications, Inc. trademarks, including the mark "WHISTLE
* COMMUNICATIONS" on advertising, endorsements, or otherwise except as
* such appears in the above copyright notice or in the software.
- *
+ *
* THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
* TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
* REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
@@ -55,6 +55,7 @@ struct console nullconsole = {
.c_out = nullc_putchar,
.c_in = nullc_getchar,
.c_ready = nullc_ischar,
+ .c_ioctl = NULL,
.c_private = NULL
};
@@ -65,26 +66,24 @@ nullc_probe(struct console *cp)
}
static int
-nullc_init(struct console *cp __attribute((unused)),
- int arg __attribute((unused)))
+nullc_init(struct console *cp __unused, int arg __unused)
{
return(0);
}
static void
-nullc_putchar(struct console *cp __attribute((unused)),
- int c __attribute((unused)))
+nullc_putchar(struct console *cp __unused, int c __unused)
{
}
static int
-nullc_getchar(struct console *cp __attribute((unused)))
+nullc_getchar(struct console *cp __unused)
{
return(-1);
}
static int
-nullc_ischar(struct console *cp __attribute((unused)))
+nullc_ischar(struct console *cp __unused)
{
return(0);
}
diff --git a/usr/src/boot/sys/boot/i386/libi386/spinconsole.c b/usr/src/boot/sys/boot/i386/libi386/spinconsole.c
index 47a85da493..ff59c7e49c 100644
--- a/usr/src/boot/sys/boot/i386/libi386/spinconsole.c
+++ b/usr/src/boot/sys/boot/i386/libi386/spinconsole.c
@@ -1,10 +1,10 @@
-/*-
+/*
* spinconsole.c
*
* Author: Maksym Sobolyev <sobomax@sippysoft.com>
* Copyright (c) 2009 Sippy Software, Inc.
* All rights reserved.
- *
+ *
* Subject to the following obligations and disclaimer of warranty, use and
* redistribution of this software, in source or object code forms, with or
* without modifications are expressly permitted by Whistle Communications;
@@ -15,7 +15,7 @@
* Communications, Inc. trademarks, including the mark "WHISTLE
* COMMUNICATIONS" on advertising, endorsements, or otherwise except as
* such appears in the above copyright notice or in the software.
- *
+ *
* THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
* TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
* REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
@@ -40,13 +40,6 @@
#include <stand.h>
#include <bootstrap.h>
-extern void get_pos(int *x, int *y);
-extern void curs_move(int *_x, int *_y, int x, int y);
-#if defined(EFI)
-extern void efi_cons_efiputchar(int c);
-#else
-extern void vidc_biosputchar(int c);
-#endif
static void spinc_probe(struct console *cp);
static int spinc_init(struct console *cp, int arg);
@@ -63,6 +56,7 @@ struct console spinconsole = {
.c_out = spinc_putchar,
.c_in = spinc_getchar,
.c_ready = spinc_ischar,
+ .c_ioctl = NULL,
.c_private = NULL
};
@@ -73,48 +67,42 @@ spinc_probe(struct console *cp)
}
static int
-spinc_init(struct console *cp __attribute((unused)),
- int arg __attribute((unused)))
+spinc_init(struct console *cp __unused, int arg __unused)
{
return(0);
}
static void
-spinc_putchar(struct console *cp __attribute((unused)),
- int c __attribute((unused)))
+spinc_putchar(struct console *cp __unused, int c __unused)
{
-#ifdef TERM_EMU
- static int curx, cury;
-#endif
static unsigned tw_chars = 0x5C2D2F7C; /* "\-/|" */
static time_t lasttime;
+ int i;
time_t now;
now = time(NULL);
if (now < (lasttime + 1))
return;
lasttime = now;
-#ifdef TERM_EMU
- get_pos(&curx, &cury);
- if (curx > 0)
- curs_move(&curx, &cury, curx - 1, cury);
-#endif
-#if defined(EFI)
- efi_cons_efiputchar((char)tw_chars);
-#else
- vidc_biosputchar((char)tw_chars);
-#endif
+ for (i = 0; consoles[i] != NULL; i++)
+ if (strcmp(consoles[i]->c_name, "text") == 0)
+ break;
+ if (consoles[i] == NULL)
+ return;
+
+ consoles[i]->c_out(consoles[i], (char)tw_chars);
+ consoles[i]->c_out(consoles[i], '\b');
tw_chars = (tw_chars >> 8) | ((tw_chars & (unsigned long)0xFF) << 24);
}
static int
-spinc_getchar(struct console *cp __attribute((unused)))
+spinc_getchar(struct console *cp __unused)
{
return(-1);
}
static int
-spinc_ischar(struct console *cp __attribute((unused)))
+spinc_ischar(struct console *cp __unused)
{
return(0);
}
diff --git a/usr/src/boot/sys/boot/i386/libi386/vbe.c b/usr/src/boot/sys/boot/i386/libi386/vbe.c
new file mode 100644
index 0000000000..7b7bad9e57
--- /dev/null
+++ b/usr/src/boot/sys/boot/i386/libi386/vbe.c
@@ -0,0 +1,813 @@
+/*
+ * Copyright (c) 2009 Jared D. McNeill <jmcneill@invisible.ca>
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * VESA BIOS Extensions routines
+ */
+
+#include <stand.h>
+#include <stdbool.h>
+#include <bootstrap.h>
+#include <machine/bootinfo.h>
+#include <machine/metadata.h>
+#include <sys/multiboot2.h>
+#include <btxv86.h>
+#include "libi386.h"
+#include "gfx_fb.h" /* for EDID */
+#include "vbe.h"
+#include <sys/vgareg.h>
+#include <sys/vgasubr.h>
+
+multiboot_tag_vbe_t vbestate;
+static struct vbeinfoblock *vbe =
+ (struct vbeinfoblock *) &vbestate.vbe_control_info;
+static struct modeinfoblock *vbe_mode =
+ (struct modeinfoblock *) &vbestate.vbe_mode_info;
+multiboot_color_t cmap[16];
+
+/* Actually assuming mode 3. */
+void
+bios_set_text_mode(int mode)
+{
+ int atr;
+
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x10;
+ v86.eax = mode; /* set VGA text mode */
+ v86int();
+ atr = vga_get_atr(VGA_REG_ADDR, VGA_ATR_MODE);
+ atr &= ~VGA_ATR_MODE_BLINK;
+ atr &= ~VGA_ATR_MODE_9WIDE;
+ vga_set_atr(VGA_REG_ADDR, VGA_ATR_MODE, atr);
+
+ vbestate.vbe_mode = 0; /* vbe is disabled */
+ gfx_fb.framebuffer_common.framebuffer_type =
+ MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT;
+ /* 16 bits per character */
+ gfx_fb.framebuffer_common.framebuffer_bpp = 16;
+ gfx_fb.framebuffer_common.framebuffer_addr =
+ VGA_MEM_ADDR + VGA_COLOR_BASE;
+ gfx_fb.framebuffer_common.framebuffer_width = TEXT_COLS;
+ gfx_fb.framebuffer_common.framebuffer_height = TEXT_ROWS;
+ gfx_fb.framebuffer_common.framebuffer_pitch = TEXT_COLS * 2;
+}
+
+/* Function 00h - Return VBE Controller Information */
+static int
+biosvbe_info(struct vbeinfoblock *vbe)
+{
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x10;
+ v86.eax = 0x4f00;
+ v86.es = VTOPSEG(vbe);
+ v86.edi = VTOPOFF(vbe);
+ v86int();
+ return (v86.eax & 0xffff);
+}
+
+/* Function 01h - Return VBE Mode Information */
+static int
+biosvbe_get_mode_info(int mode, struct modeinfoblock *mi)
+{
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x10;
+ v86.eax = 0x4f01;
+ v86.ecx = mode;
+ v86.es = VTOPSEG(mi);
+ v86.edi = VTOPOFF(mi);
+ v86int();
+ return (v86.eax & 0xffff);
+}
+
+/* Function 02h - Set VBE Mode */
+static int
+biosvbe_set_mode(int mode, struct crtciinfoblock *ci)
+{
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x10;
+ v86.eax = 0x4f02;
+ v86.ebx = mode | 0x4000; /* set linear FB bit */
+ v86.es = VTOPSEG(ci);
+ v86.edi = VTOPOFF(ci);
+ v86int();
+ return (v86.eax & 0xffff);
+}
+
+/* Function 03h - Get VBE Mode */
+static int
+biosvbe_get_mode(int *mode)
+{
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x10;
+ v86.eax = 0x4f03;
+ v86int();
+ *mode = v86.ebx & 0xffff;
+ return (v86.eax & 0xffff);
+}
+
+/* Function 08h - Set/Get DAC Palette Format */
+int
+biosvbe_palette_format(int *format)
+{
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x10;
+ v86.eax = 0x4f08;
+ v86.ebx = *format;
+ v86int();
+ *format = v86.ebx & 0xffff;
+ return (v86.eax & 0xffff);
+}
+
+/* Function 09h - Set/Get Palette Data */
+static int
+biosvbe_palette_data(int mode, int reg, struct paletteentry *pe)
+{
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x10;
+ v86.eax = 0x4f09;
+ v86.ebx = mode;
+ v86.edx = reg;
+ v86.ecx = 1;
+ v86.es = VTOPSEG(pe);
+ v86.edi = VTOPOFF(pe);
+ v86int();
+ return (v86.eax & 0xffff);
+}
+
+/*
+ * Function 15h BL=00h - Report VBE/DDC Capabilities
+ *
+ * int biosvbe_ddc_caps(void)
+ * return: VBE/DDC capabilities
+ */
+static int
+biosvbe_ddc_caps(void)
+{
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x10;
+ v86.eax = 0x4f15; /* display identification extensions */
+ v86.ebx = 0; /* report DDC capabilities */
+ v86.ecx = 0; /* controller unit number (00h = primary) */
+ v86.es = 0;
+ v86.edi = 0;
+ v86int();
+ if (VBE_ERROR(v86.eax & 0xffff))
+ return (0);
+ return (v86.ebx & 0xffff);
+}
+
+/* Function 15h BL=01h - Read EDID */
+static int
+biosvbe_ddc_read_edid(int blockno, void *buf)
+{
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x10;
+ v86.eax = 0x4f15; /* display identification extensions */
+ v86.ebx = 1; /* read EDID */
+ v86.ecx = 0; /* controller unit number (00h = primary) */
+ v86.edx = blockno;
+ v86.es = VTOPSEG(buf);
+ v86.edi = VTOPOFF(buf);
+ v86int();
+ return (v86.eax & 0xffff);
+}
+
+static int
+vbe_mode_is_supported(struct modeinfoblock *mi)
+{
+ if ((mi->ModeAttributes & 0x01) == 0)
+ return 0; /* mode not supported by hardware */
+ if ((mi->ModeAttributes & 0x08) == 0)
+ return 0; /* linear fb not available */
+ if ((mi->ModeAttributes & 0x10) == 0)
+ return 0; /* text mode */
+ if (mi->NumberOfPlanes != 1)
+ return 0; /* planar mode not supported */
+ if (mi->MemoryModel != 0x04 /* Packed pixel */ &&
+ mi->MemoryModel != 0x06 /* Direct Color */)
+ return 0; /* unsupported pixel format */
+ return 1;
+}
+
+static int
+vbe_check(void)
+{
+ if (vbestate.mb_type != MULTIBOOT_TAG_TYPE_VBE) {
+ printf("VBE not available\n");
+ return (0);
+ }
+ return (1);
+}
+
+void
+vbe_init(void)
+{
+ /* First set FB for text mode. */
+ gfx_fb.framebuffer_common.mb_type = MULTIBOOT_TAG_TYPE_FRAMEBUFFER;
+ gfx_fb.framebuffer_common.framebuffer_type =
+ MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT;
+ /* 16 bits per character */
+ gfx_fb.framebuffer_common.framebuffer_bpp = 16;
+ gfx_fb.framebuffer_common.framebuffer_addr =
+ VGA_MEM_ADDR + VGA_COLOR_BASE;
+ gfx_fb.framebuffer_common.framebuffer_width = TEXT_COLS;
+ gfx_fb.framebuffer_common.framebuffer_height = TEXT_ROWS;
+ gfx_fb.framebuffer_common.framebuffer_pitch = TEXT_COLS * 2;
+
+ /* Now check if we have vesa. */
+ memset(vbe, 0, sizeof(*vbe));
+ memcpy(vbe->VbeSignature, "VBE2", 4);
+ if (biosvbe_info(vbe) != VBE_SUCCESS)
+ return;
+ if (memcmp(vbe->VbeSignature, "VESA", 4) != 0)
+ return;
+
+ vbestate.mb_type = MULTIBOOT_TAG_TYPE_VBE;
+ vbestate.mb_size = sizeof (vbestate);
+ vbestate.vbe_mode = 0;
+ /* vbe_set_mode() will set up the rest. */
+}
+
+int
+vbe_available(void)
+{
+ return vbestate.mb_type;
+}
+
+int
+vbe_set_palette(const struct paletteentry *entry, size_t slot)
+{
+ struct paletteentry pe;
+ int ret;
+
+ if (!vbe_check())
+ return (1);
+
+ if (gfx_fb.framebuffer_common.framebuffer_type !=
+ MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED) {
+ return (1);
+ }
+
+ pe.Blue = entry->Blue;
+ pe.Green = entry->Green;
+ pe.Red = entry->Red;
+ pe.Alignment = entry->Alignment;
+
+ ret = biosvbe_palette_data(0x00, slot, &pe);
+ if (ret == VBE_SUCCESS && slot < sizeof (cmap)) {
+ cmap[slot].mb_red = entry->Red;
+ cmap[slot].mb_green = entry->Green;
+ cmap[slot].mb_blue = entry->Blue;
+ }
+
+ return (ret == VBE_SUCCESS ? 0 : 1);
+}
+
+int
+vbe_get_mode(void)
+{
+ return vbestate.vbe_mode;
+}
+
+int
+vbe_set_mode(int modenum)
+{
+ struct modeinfoblock mi;
+ int ret;
+
+ if (!vbe_check())
+ return (1);
+
+ ret = biosvbe_get_mode_info(modenum, &mi);
+ if (VBE_ERROR(ret)) {
+ printf("mode 0x%x invalid\n", modenum);
+ return (1);
+ }
+
+ if (!vbe_mode_is_supported(&mi)) {
+ printf("mode 0x%x not supported\n", modenum);
+ return (1);
+ }
+
+ /* calculate bytes per pixel */
+ switch (mi.BitsPerPixel) {
+ case 32:
+ case 24:
+ case 16:
+ case 15:
+ case 8:
+ break;
+ default:
+ printf("BitsPerPixel %d is not supported\n", mi.BitsPerPixel);
+ return (1);
+ }
+
+ ret = biosvbe_set_mode(modenum, NULL);
+ if (VBE_ERROR(ret)) {
+ printf("mode 0x%x could not be set\n", modenum);
+ return (1);
+ }
+
+ /* make sure we have current MI in vbestate */
+ memcpy(vbe_mode, &mi, sizeof (*vbe_mode));
+ vbestate.vbe_mode = modenum;
+
+ gfx_fb.framebuffer_common.framebuffer_addr =
+ (uint64_t)mi.PhysBasePtr & 0xffffffff;
+ gfx_fb.framebuffer_common.framebuffer_width = mi.XResolution;
+ gfx_fb.framebuffer_common.framebuffer_height = mi.YResolution;
+ gfx_fb.framebuffer_common.framebuffer_bpp = mi.BitsPerPixel;
+
+ /* vbe_mode_is_supported() excludes the rest */
+ switch (mi.MemoryModel) {
+ case 0x4:
+ gfx_fb.framebuffer_common.framebuffer_type =
+ MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED;
+ if (vbe->VbeVersion >= 0x300) {
+ gfx_fb.framebuffer_common.framebuffer_pitch =
+ mi.LinBytesPerScanLine;
+ } else {
+ gfx_fb.framebuffer_common.framebuffer_pitch =
+ mi.BytesPerScanLine;
+ }
+ gfx_fb.u.fb1.framebuffer_palette_num_colors = 16;
+ return (0); /* done */
+ case 0x6:
+ gfx_fb.framebuffer_common.framebuffer_type =
+ MULTIBOOT_FRAMEBUFFER_TYPE_RGB;
+ break;
+ }
+
+ if (vbe->VbeVersion >= 0x300) {
+ gfx_fb.framebuffer_common.framebuffer_pitch =
+ mi.LinBytesPerScanLine;
+ gfx_fb.u.fb2.framebuffer_red_field_position =
+ mi.LinRedFieldPosition;
+ gfx_fb.u.fb2.framebuffer_red_mask_size = mi.LinRedMaskSize;
+ gfx_fb.u.fb2.framebuffer_green_field_position =
+ mi.LinGreenFieldPosition;
+ gfx_fb.u.fb2.framebuffer_green_mask_size = mi.LinGreenMaskSize;
+ gfx_fb.u.fb2.framebuffer_blue_field_position =
+ mi.LinBlueFieldPosition;
+ gfx_fb.u.fb2.framebuffer_blue_mask_size = mi.LinBlueMaskSize;
+ } else {
+ gfx_fb.framebuffer_common.framebuffer_pitch =
+ mi.BytesPerScanLine;
+ gfx_fb.u.fb2.framebuffer_red_field_position =
+ mi.RedFieldPosition;
+ gfx_fb.u.fb2.framebuffer_red_mask_size = mi.RedMaskSize;
+ gfx_fb.u.fb2.framebuffer_green_field_position =
+ mi.GreenFieldPosition;
+ gfx_fb.u.fb2.framebuffer_green_mask_size = mi.GreenMaskSize;
+ gfx_fb.u.fb2.framebuffer_blue_field_position =
+ mi.BlueFieldPosition;
+ gfx_fb.u.fb2.framebuffer_blue_mask_size = mi.BlueMaskSize;
+ }
+
+ return (0);
+}
+
+static void *
+vbe_farptr(uint32_t farptr)
+{
+ return PTOV((((farptr & 0xffff0000) >> 12) + (farptr & 0xffff)));
+}
+
+/*
+ * Verify existance of mode number or find mode by
+ * dimensions. If depth is not given, walk values 32, 24, 16, 8.
+ */
+static int
+vbe_find_mode_xydm(int x, int y, int depth, int m)
+{
+ struct modeinfoblock mi;
+ uint32_t farptr;
+ uint16_t mode;
+ int safety = 0, i;
+
+ memset(vbe, 0, sizeof(vbe));
+ memcpy(vbe->VbeSignature, "VBE2", 4);
+ if (biosvbe_info(vbe) != VBE_SUCCESS)
+ return (0);
+ if (memcmp(vbe->VbeSignature, "VESA", 4) != 0)
+ return (0);
+ farptr = vbe->VideoModePtr;
+ if (farptr == 0)
+ return (0);
+
+ if (m != -1)
+ i = 8;
+ else if (depth == -1)
+ i = 32;
+ else
+ i = depth;
+
+ while (i > 0) {
+ while ((mode = *(uint16_t *)vbe_farptr(farptr)) != 0xffff) {
+ safety++;
+ farptr += 2;
+ if (safety == 100)
+ return 0;
+ if (biosvbe_get_mode_info(mode, &mi) != VBE_SUCCESS) {
+ continue;
+ }
+ /* we only care about linear modes here */
+ if (vbe_mode_is_supported(&mi) == 0)
+ continue;
+ safety = 0;
+
+ if (m != -1) {
+ if (m == mode)
+ return (mode);
+ else
+ continue;
+ }
+
+ if (mi.XResolution == x &&
+ mi.YResolution == y &&
+ mi.BitsPerPixel == i)
+ return mode;
+ }
+ if (depth != -1)
+ break;
+
+ i -= 8;
+ }
+
+ return (0);
+}
+
+static int
+vbe_find_mode(char *str)
+{
+ int x, y, depth;
+
+ if (!gfx_parse_mode_str(str, &x, &y, &depth))
+ return (0);
+
+ return (vbe_find_mode_xydm(x, y, depth, -1));
+}
+
+static void
+vbe_dump_mode(int modenum, struct modeinfoblock *mi)
+{
+ printf("0x%x=%dx%dx%d", modenum,
+ mi->XResolution, mi->YResolution, mi->BitsPerPixel);
+}
+
+static bool
+vbe_get_edid(uint_t *pwidth, uint_t *pheight)
+{
+ struct vesa_edid_info edid_info;
+ const uint8_t magic[] = EDID_MAGIC;
+ int ddc_caps, ret;
+
+ ddc_caps = biosvbe_ddc_caps();
+ if (ddc_caps == 0) {
+ return (false);
+ }
+
+ ret = biosvbe_ddc_read_edid(0, &edid_info);
+ if (VBE_ERROR(ret))
+ return (false);
+
+ if (memcmp(&edid_info, magic, sizeof (magic)) != 0)
+ return (false);
+
+ if (!(edid_info.header.version == 1 &&
+ (edid_info.display.supported_features
+ & EDID_FEATURE_PREFERRED_TIMING_MODE) &&
+ edid_info.detailed_timings[0].pixel_clock))
+ return (false);
+
+ *pwidth = edid_info.detailed_timings[0].horizontal_active_lo |
+ (((uint_t)edid_info.detailed_timings[0].horizontal_hi & 0xf0) << 4);
+ *pheight = edid_info.detailed_timings[0].vertical_active_lo |
+ (((uint_t)edid_info.detailed_timings[0].vertical_hi & 0xf0) << 4);
+
+ return (true);
+}
+
+static void
+vbe_print_vbe_info(struct vbeinfoblock *vbep)
+{
+ char *oemstring = "";
+ char *oemvendor = "", *oemproductname = "", *oemproductrev = "";
+
+ if (vbep->OemStringPtr != 0)
+ oemstring = vbe_farptr(vbep->OemStringPtr);
+
+ if (vbep->OemVendorNamePtr != 0)
+ oemvendor = vbe_farptr(vbep->OemVendorNamePtr);
+
+ if (vbep->OemProductNamePtr != 0)
+ oemproductname = vbe_farptr(vbep->OemProductNamePtr);
+
+ if (vbep->OemProductRevPtr != 0)
+ oemproductrev = vbe_farptr(vbep->OemProductRevPtr);
+
+ printf("VESA VBE Version %d.%d\n%s\n", vbep->VbeVersion >> 8,
+ vbep->VbeVersion & 0xF, oemstring);
+
+ if (vbep->OemSoftwareRev != 0) {
+ printf("OEM Version %d.%d, %s (%s, %s)\n",
+ vbep->OemSoftwareRev >> 8, vbep->OemSoftwareRev & 0xF,
+ oemvendor, oemproductname, oemproductrev);
+ }
+}
+
+/* List available modes, filter by depth. If depth is -1, list all. */
+void
+vbe_modelist(int depth)
+{
+ struct modeinfoblock mi;
+ uint32_t farptr;
+ uint16_t mode;
+ int nmodes = 0, safety = 0;
+ int ddc_caps;
+ uint_t edid_width, edid_height;
+
+ if (!vbe_check())
+ return;
+
+ ddc_caps = biosvbe_ddc_caps();
+ if (ddc_caps & 3) {
+ printf("DDC");
+ if (ddc_caps & 1)
+ printf(" [DDC1]");
+ if (ddc_caps & 2)
+ printf(" [DDC2]");
+
+ if (vbe_get_edid(&edid_width, &edid_height))
+ printf(": EDID %dx%d\n", edid_width, edid_height);
+ else
+ printf(": no EDID information\n");
+ }
+
+ memset(vbe, 0, sizeof(vbe));
+ memcpy(vbe->VbeSignature, "VBE2", 4);
+ if (biosvbe_info(vbe) != VBE_SUCCESS)
+ goto done;
+ if (memcmp(vbe->VbeSignature, "VESA", 4) != 0)
+ goto done;
+
+ vbe_print_vbe_info(vbe);
+ printf("Modes: ");
+
+ farptr = vbe->VideoModePtr;
+ if (farptr == 0)
+ goto done;
+
+ while ((mode = *(uint16_t *)vbe_farptr(farptr)) != 0xffff) {
+ safety++;
+ farptr += 2;
+ if (safety == 100) {
+ printf("[?] ");
+ break;
+ }
+ if (biosvbe_get_mode_info(mode, &mi) != VBE_SUCCESS)
+ continue;
+ /* we only care about linear modes here */
+ if (vbe_mode_is_supported(&mi) == 0)
+ continue;
+
+ /* we found some mode so reset safety counter */
+ safety = 0;
+
+ /* apply requested filter */
+ if (depth != -1 && mi.BitsPerPixel != depth)
+ continue;
+
+ if (nmodes % 4 == 0)
+ printf("\n");
+ else
+ printf(" ");
+
+ vbe_dump_mode(mode, &mi);
+ nmodes++;
+ }
+
+done:
+ if (nmodes == 0)
+ printf("none found");
+ printf("\n");
+}
+
+static void
+vbe_print_mode(void)
+{
+ int mode, i, rc;
+ struct paletteentry pe;
+
+ memset(vbe, 0, sizeof(vbe));
+ memcpy(vbe->VbeSignature, "VBE2", 4);
+ if (biosvbe_info(vbe) != VBE_SUCCESS)
+ return;
+
+ if (memcmp(vbe->VbeSignature, "VESA", 4) != 0)
+ return;
+
+ vbe_print_vbe_info(vbe);
+
+ if (biosvbe_get_mode(&mode) != VBE_SUCCESS) {
+ printf("Error getting current VBE mode\n");
+ return;
+ }
+
+ if (biosvbe_get_mode_info(mode, vbe_mode) != VBE_SUCCESS ||
+ vbe_mode_is_supported(vbe_mode) == 0) {
+ printf("VBE mode (0x%x) is not framebuffer mode\n", mode);
+ return;
+ }
+
+ printf("\nCurrent VBE mode: ");
+ vbe_dump_mode(mode, vbe_mode);
+ printf("\n");
+
+ printf("%ux%ux%u, stride=%u",
+ gfx_fb.framebuffer_common.framebuffer_width,
+ gfx_fb.framebuffer_common.framebuffer_height,
+ gfx_fb.framebuffer_common.framebuffer_bpp,
+ (gfx_fb.framebuffer_common.framebuffer_pitch << 3) /
+ gfx_fb.framebuffer_common.framebuffer_bpp);
+ printf("\n frame buffer: address=%jx, size=%jx",
+ (uintmax_t) gfx_fb.framebuffer_common.framebuffer_addr,
+ (uintmax_t) gfx_fb.framebuffer_common.framebuffer_height *
+ gfx_fb.framebuffer_common.framebuffer_pitch);
+
+ if (vbe_mode->MemoryModel == 0x6) {
+ printf("\n color mask: R=%08x, G=%08x, B=%08x\n",
+ ((1 << gfx_fb.u.fb2.framebuffer_red_mask_size) - 1) <<
+ gfx_fb.u.fb2.framebuffer_red_field_position,
+ ((1 << gfx_fb.u.fb2.framebuffer_green_mask_size) - 1) <<
+ gfx_fb.u.fb2.framebuffer_green_field_position,
+ ((1 << gfx_fb.u.fb2.framebuffer_blue_mask_size) - 1) <<
+ gfx_fb.u.fb2.framebuffer_blue_field_position);
+ return;
+ }
+
+ mode = 1; /* get DAC palette width */
+ rc = biosvbe_palette_format(&mode);
+ if (rc != VBE_SUCCESS)
+ return;
+
+ printf(" palette format: %x bits per primary\n", mode >> 8);
+ for (i = 0; i < 16; i++) {
+ rc = biosvbe_palette_data(1, i, &pe);
+ if (rc != VBE_SUCCESS)
+ break;
+
+ printf("%d: R=%02x, G=%02x, B=%02x\n", i,
+ pe.Red, pe.Green, pe.Blue);
+ }
+}
+
+int
+vbe_default_mode(void)
+{
+ int modenum;
+ uint_t edid_width, edid_height;
+
+ if (vbe_get_edid(&edid_width, &edid_height)) {
+ modenum = vbe_find_mode_xydm(edid_width, edid_height, -1, -1);
+ if (modenum == 0)
+ modenum = vbe_find_mode(VBE_DEFAULT_MODE);
+ } else {
+ modenum = vbe_find_mode(VBE_DEFAULT_MODE);
+ }
+ return (modenum);
+}
+
+COMMAND_SET(framebuffer, "framebuffer", "framebuffer mode management",
+ command_vesa);
+
+int
+command_vesa(int argc, char *argv[])
+{
+ char *arg, *cp;
+ int modenum = -1, n;
+
+ if (!vbe_check())
+ return (CMD_OK);
+
+ if (argc < 2)
+ goto usage;
+
+ if (strcmp(argv[1], "list") == 0) {
+ n = -1;
+ if (argc != 2 && argc != 3)
+ goto usage;
+
+ if (argc == 3) {
+ arg = argv[2];
+ errno = 0;
+ n = strtoul(arg, &cp, 0);
+ if (errno != 0 || *arg == '\0' || cp[0] != '\0') {
+ snprintf(command_errbuf,
+ sizeof (command_errbuf),
+ "depth should be an integer");
+ return (CMD_ERROR);
+ }
+ }
+ vbe_modelist(n);
+ return (CMD_OK);
+ }
+
+ if (strcmp(argv[1], "get") == 0) {
+ if (argc != 2)
+ goto usage;
+
+ vbe_print_mode();
+ return (CMD_OK);
+ }
+
+ if (strcmp(argv[1], "off") == 0) {
+ if (argc != 2)
+ goto usage;
+
+ if (vbestate.vbe_mode == 0)
+ return (CMD_OK);
+
+ bios_set_text_mode(VGA_TEXT_MODE);
+ plat_cons_update_mode(0);
+ return (CMD_OK);
+ }
+
+ if (strcmp(argv[1], "on") == 0) {
+ if (argc != 2)
+ goto usage;
+
+ modenum = vbe_default_mode();
+ if (modenum == 0) {
+ snprintf(command_errbuf, sizeof (command_errbuf),
+ "%s: no suitable VBE mode number found", argv[0]);
+ return (CMD_ERROR);
+ }
+ } else if (strcmp(argv[1], "set") == 0) {
+ if (argc != 3)
+ goto usage;
+
+ if (strncmp(argv[2], "0x", 2) == 0) {
+ arg = argv[2];
+ errno = 0;
+ n = strtoul(arg, &cp, 0);
+ if (errno != 0 || *arg == '\0' || cp[0] != '\0') {
+ snprintf(command_errbuf,
+ sizeof (command_errbuf),
+ "mode should be an integer");
+ return (CMD_ERROR);
+ }
+ modenum = vbe_find_mode_xydm(0, 0, 0, n);
+ } else if (strchr(argv[2], 'x') != NULL) {
+ modenum = vbe_find_mode(argv[2]);
+ }
+ }
+
+ if (modenum == 0) {
+ snprintf(command_errbuf, sizeof (command_errbuf),
+ "%s: mode %s not supported by firmware\n",
+ argv[0], argv[2]);
+ return (CMD_ERROR);
+ }
+
+ if (modenum >= 0x100) {
+ if (vbestate.vbe_mode != modenum) {
+ vbe_set_mode(modenum);
+ plat_cons_update_mode(1);
+ }
+ return (CMD_OK);
+ } else {
+ snprintf(command_errbuf, sizeof (command_errbuf),
+ "%s: mode %s is not framebuffer mode\n", argv[0], argv[2]);
+ return (CMD_ERROR);
+ }
+
+usage:
+ snprintf(command_errbuf, sizeof (command_errbuf),
+ "usage: %s on | off | get | list [depth] | "
+ "set <display or VBE mode number>", argv[0]);
+ return (CMD_ERROR);
+}
diff --git a/usr/src/boot/sys/boot/i386/libi386/vbe.h b/usr/src/boot/sys/boot/i386/libi386/vbe.h
new file mode 100644
index 0000000000..7b428b968d
--- /dev/null
+++ b/usr/src/boot/sys/boot/i386/libi386/vbe.h
@@ -0,0 +1,145 @@
+/*-
+ * Copyright (c) 2009 Jared D. McNeill <jmcneill@invisible.ca>
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * Default mode for VESA frame buffer.
+ * This mode is selected when there is no EDID inormation and
+ * mode is not provided by user.
+ * To provide consistent look with UEFI GOP, we use 800x600 here,
+ * and if this mode is not available, we fall back to text mode and
+ * VESA disabled.
+ */
+
+#define VBE_DEFAULT_MODE "800x600"
+
+struct vbeinfoblock {
+ char VbeSignature[4];
+ uint16_t VbeVersion;
+ uint32_t OemStringPtr;
+ uint32_t Capabilities;
+ uint32_t VideoModePtr;
+ uint16_t TotalMemory;
+ uint16_t OemSoftwareRev;
+ uint32_t OemVendorNamePtr, OemProductNamePtr, OemProductRevPtr;
+ /* data area, in total max 512 bytes for VBE 2.0 */
+ uint8_t Reserved[222];
+ uint8_t OemData[256];
+} __packed;
+
+struct modeinfoblock {
+ /* Mandatory information for all VBE revisions */
+ uint16_t ModeAttributes;
+ uint8_t WinAAttributes, WinBAttributes;
+ uint16_t WinGranularity, WinSize, WinASegment, WinBSegment;
+ uint32_t WinFuncPtr;
+ uint16_t BytesPerScanLine;
+ /* Mandatory information for VBE 1.2 and above */
+ uint16_t XResolution, YResolution;
+ uint8_t XCharSize, YCharSize, NumberOfPlanes, BitsPerPixel;
+ uint8_t NumberOfBanks, MemoryModel, BankSize, NumberOfImagePages;
+ uint8_t Reserved1;
+ /* Direct Color fields
+ (required for direct/6 and YUV/7 memory models) */
+ uint8_t RedMaskSize, RedFieldPosition;
+ uint8_t GreenMaskSize, GreenFieldPosition;
+ uint8_t BlueMaskSize, BlueFieldPosition;
+ uint8_t RsvdMaskSize, RsvdFieldPosition;
+ uint8_t DirectColorModeInfo;
+ /* Mandatory information for VBE 2.0 and above */
+ uint32_t PhysBasePtr;
+ uint32_t OffScreenMemOffset; /* reserved in VBE 3.0 and above */
+ uint16_t OffScreenMemSize; /* reserved in VBE 3.0 and above */
+
+ /* Mandatory information for VBE 3.0 and above */
+ uint16_t LinBytesPerScanLine;
+ uint8_t BnkNumberOfImagePages;
+ uint8_t LinNumberOfImagePages;
+ uint8_t LinRedMaskSize, LinRedFieldPosition;
+ uint8_t LinGreenMaskSize, LinGreenFieldPosition;
+ uint8_t LinBlueMaskSize, LinBlueFieldPosition;
+ uint8_t LinRsvdMaskSize, LinRsvdFieldPosition;
+ uint32_t MaxPixelClock;
+ /* + 1 will fix the size to 256 bytes */
+ uint8_t Reserved4[189 + 1];
+} __packed;
+
+struct crtciinfoblock {
+ uint16_t HorizontalTotal;
+ uint16_t HorizontalSyncStart;
+ uint16_t HorizontalSyncEnd;
+ uint16_t VerticalTotal;
+ uint16_t VerticalSyncStart;
+ uint16_t VerticalSyncEnd;
+ uint8_t Flags;
+ uint32_t PixelClock;
+ uint16_t RefreshRate;
+ uint8_t Reserved[40];
+} __packed;
+
+struct paletteentry {
+ uint8_t Blue;
+ uint8_t Green;
+ uint8_t Red;
+ uint8_t Alignment;
+} __packed;
+
+struct flatpanelinfo
+{
+ uint16_t HorizontalSize;
+ uint16_t VerticalSize;
+ uint16_t PanelType;
+ uint8_t RedBPP;
+ uint8_t GreenBPP;
+ uint8_t BlueBPP;
+ uint8_t ReservedBPP;
+ uint32_t ReservedOffScreenMemSize;
+ uint32_t ReservedOffScreenMemPtr;
+
+ uint8_t Reserved[14];
+} __packed;
+
+#define VBE_BASE_MODE (0x100) /* VBE 3.0 page 18 */
+#define VBE_VALID_MODE(a) ((a) >= VBE_BASE_MODE)
+#define VBE_ERROR(a) (((a) & 0xFF) != 0x4F || ((a) & 0xFF00) != 0)
+#define VBE_SUCCESS (0x004F)
+#define VBE_FAILED (0x014F)
+#define VBE_NOTSUP (0x024F)
+#define VBE_INVALID (0x034F)
+
+#define VGA_TEXT_MODE (3) /* 80x25 text mode */
+#define TEXT_ROWS (25) /* VGATEXT rows */
+#define TEXT_COLS (80) /* VGATEXT columns */
+
+/* high-level VBE helpers, from vbe.c */
+void bios_set_text_mode(int);
+int biosvbe_palette_format(int *);
+void vbe_init(void);
+int vbe_available(void);
+int vbe_default_mode(void);
+int vbe_set_mode(int);
+int vbe_get_mode(void);
+int vbe_set_palette(const struct paletteentry *, size_t);
+void vbe_modelist(int);
diff --git a/usr/src/boot/sys/boot/i386/libi386/vidconsole.c b/usr/src/boot/sys/boot/i386/libi386/vidconsole.c
index edefda223c..0bfb39649e 100644
--- a/usr/src/boot/sys/boot/i386/libi386/vidconsole.c
+++ b/usr/src/boot/sys/boot/i386/libi386/vidconsole.c
@@ -1,4 +1,4 @@
-/*-
+/*
* Copyright (c) 1998 Michael Smith (msmith@freebsd.org)
* Copyright (c) 1997 Kazutaka YOKOTA (yokota@zodiac.mech.utsunomiya-u.ac.jp)
* All rights reserved.
@@ -24,19 +24,27 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * Id: probe_keyboard.c,v 1.13 1997/06/09 05:10:55 bde Exp
+ * Id: probe_keyboard.c,v 1.13 1997/06/09 05:10:55 bde Exp
*/
#include <sys/cdefs.h>
#include <stand.h>
#include <bootstrap.h>
+#include <sys/tem_impl.h>
+#include <sys/visual_io.h>
+#include <sys/multiboot2.h>
#include <btxv86.h>
#include <machine/psl.h>
+#include <machine/metadata.h>
#include "libi386.h"
+#include "vbe.h"
+#include <gfx_fb.h>
+#include <sys/vgareg.h>
+#include <sys/vgasubr.h>
+#include <machine/cpufunc.h>
#if KEYBOARD_PROBE
-#include <machine/cpufunc.h>
static int probe_keyboard(void);
#endif
@@ -45,605 +53,734 @@ static int vidc_init(struct console *cp, int arg);
static void vidc_putchar(struct console *cp, int c);
static int vidc_getchar(struct console *cp);
static int vidc_ischar(struct console *cp);
+static int vidc_ioctl(struct console *cp, int cmd, void *data);
+static void vidc_biosputchar(int c);
+
+static int vidc_vbe_devinit(struct vis_devinit *);
+static void vidc_cons_cursor(struct vis_conscursor *);
+static int vidc_vbe_cons_put_cmap(struct vis_cmap *);
+
+static int vidc_text_devinit(struct vis_devinit *);
+static int vidc_text_cons_clear(struct vis_consclear *);
+static void vidc_text_cons_copy(struct vis_conscopy *);
+static void vidc_text_cons_display(struct vis_consdisplay *);
+static void vidc_text_set_cursor(screen_pos_t, screen_pos_t, boolean_t);
+static void vidc_text_get_cursor(screen_pos_t *, screen_pos_t *);
+static int vidc_text_cons_put_cmap(struct vis_cmap *);
+
+static int vidc_started;
+static uint16_t *vgatext;
-static int vidc_started;
+/* 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;
-#ifdef TERM_EMU
-#define MAXARGS 8
#define KEYBUFSZ 10
#define DEFAULT_FGCOLOR 7
#define DEFAULT_BGCOLOR 0
-void end_term(void);
-void bail_out(int c);
-void vidc_term_emu(int c);
-void get_pos(int *x, int *y);
-void curs_move(int *_x, int *_y, int x, int y);
-void write_char(int c, int fg, int bg);
-void scroll_up(int rows, int fg, int bg);
-void CD(void);
-void CM(void);
-void HO(void);
-
-static unsigned keybuf[KEYBUFSZ]; /* keybuf for extended codes */
-static int args[MAXARGS], argc;
-static int fg_c, bg_c, curx, cury;
-static int esc;
-#endif
-
+static uint8_t keybuf[KEYBUFSZ]; /* keybuf for extended codes */
struct console text = {
- "text",
- "internal video/keyboard",
- 0,
- vidc_probe,
- vidc_init,
- vidc_putchar,
- vidc_getchar,
- vidc_ischar,
- NULL
+ .c_name = "text",
+ .c_desc = "internal video/keyboard",
+ .c_flags = 0,
+ .c_probe = vidc_probe,
+ .c_init = vidc_init,
+ .c_out = vidc_putchar,
+ .c_in = vidc_getchar,
+ .c_ready = vidc_ischar,
+ .c_ioctl = vidc_ioctl,
+ .c_private = NULL
};
-static void
-vidc_probe(struct console *cp)
-{
-
- /* look for a keyboard */
-#if KEYBOARD_PROBE
- if (probe_keyboard())
-#endif
- {
-
- cp->c_flags |= C_PRESENTIN;
- }
+static struct vis_identifier fb_ident = { "vidc_fb" };
+static struct vis_identifier text_ident = { "vidc_text" };
+
+struct visual_ops fb_ops = {
+ .ident = &fb_ident,
+ .kdsetmode = NULL,
+ .devinit = vidc_vbe_devinit,
+ .cons_copy = NULL,
+ .cons_display = NULL,
+ .cons_cursor = vidc_cons_cursor,
+ .cons_clear = NULL,
+ .cons_put_cmap = vidc_vbe_cons_put_cmap
+};
- /* XXX for now, always assume we can do BIOS screen output */
- cp->c_flags |= C_PRESENTOUT;
-}
+struct visual_ops text_ops = {
+ .ident = &text_ident,
+ .kdsetmode = NULL,
+ .devinit = vidc_text_devinit,
+ .cons_copy = vidc_text_cons_copy,
+ .cons_display = vidc_text_cons_display,
+ .cons_cursor = vidc_cons_cursor,
+ .cons_clear = vidc_text_cons_clear,
+ .cons_put_cmap = vidc_text_cons_put_cmap
+};
-static int
-vidc_init(struct console *cp, int arg)
+/*
+ * platform specific functions for tem
+ */
+int
+plat_stdout_is_framebuffer(void)
{
- int i;
-
- if (vidc_started && arg == 0)
- return (0);
- vidc_started = 1;
-#ifdef TERM_EMU
- /* Init terminal emulator */
- 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
- for (i = 0; i < 10 && vidc_ischar(cp); i++)
- (void)vidc_getchar(cp);
- return (0); /* XXX reinit? */
+ if (vbe_available() && VBE_VALID_MODE(vbe_get_mode())) {
+ return (1);
+ }
+ return (0);
}
void
-vidc_biosputchar(int c)
+plat_tem_hide_prom_cursor(void)
{
-
- v86.ctl = 0;
- v86.addr = 0x10;
- v86.eax = 0xe00 | (c & 0xff);
- v86.ebx = 0x7;
- v86int();
+ vidc_text_set_cursor(0, 0, B_FALSE);
}
-static void
-vidc_rawputchar(int c)
+void
+plat_tem_get_prom_pos(uint32_t *row, uint32_t *col)
{
- int i;
-
- if (c == '\t')
- /* lame tab expansion */
- for (i = 0; i < 8; i++)
- vidc_rawputchar(' ');
- else {
-#ifndef TERM_EMU
- vidc_biosputchar(c);
-#else
- /* Emulate AH=0eh (teletype output) */
- switch(c) {
- case '\a':
- vidc_biosputchar(c);
- return;
- case '\r':
- curx = 0;
- break;
- case '\n':
- cury++;
- if ((text.c_flags & C_MODERAW) == 0)
- curx = 0;
-
- if (cury > 24) {
- scroll_up(1, fg_c, bg_c);
- cury--;
- }
- break;
- case '\b':
- if (curx > 0)
- curx--;
- break;
- default:
- if (curx > 79) {
- curx = 0;
- cury++;
- curs_move(&curx, &cury, curx, cury);
- }
- if ((text.c_flags & C_MODERAW) == 0) {
- if (cury > 24) {
- curx = 0;
- scroll_up(1, fg_c, bg_c);
- cury--;
- curs_move(&curx, &cury, curx, cury);
- }
- }
- write_char(c, fg_c, bg_c);
- curx++;
- if (text.c_flags & C_MODERAW) {
- if (curx > 79) {
- curx = 0;
- if (cury == 25)
- scroll_up(1, fg_c, bg_c);
- else
- cury++;
- }
- }
+ screen_pos_t x, y;
+
+ if (plat_stdout_is_framebuffer()) {
+ *row = 0;
+ *col = 0;
+ } else {
+ vidc_text_get_cursor(&y, &x);
+ *row = (uint32_t) y;
+ *col = (uint32_t) x;
}
- curs_move(&curx, &cury, curx, cury);
-#endif
- }
}
-#ifdef TERM_EMU
-
-/* Get cursor position on the screen. Result is in edx. Sets
- * curx and cury appropriately.
+/*
+ * 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
-get_pos(int *x, int *y)
+plat_tem_get_prom_size(size_t *height, size_t *width)
{
-
- v86.ctl = 0;
- v86.addr = 0x10;
- v86.eax = 0x0300;
- v86.ebx = 0x0;
- v86int();
- *x = v86.edx & 0x00ff;
- *y = (v86.edx & 0xff00) >> 8;
+ if (plat_stdout_is_framebuffer()) {
+ *height = TEM_DEFAULT_ROWS;
+ *width = TEM_DEFAULT_COLS;
+ } else {
+ *height = TEXT_ROWS;
+ *width = TEXT_COLS;
+ }
}
-/* Move cursor to x rows and y cols (0-based). */
void
-curs_move(int *_x, int *_y, int x, int y)
+plat_cons_update_mode(int mode __unused)
{
+ struct vis_devinit devinit;
+
+ if (tem == NULL) /* tem is not set up */
+ return;
+
+ if (plat_stdout_is_framebuffer()) {
+ 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;
+ text.c_private = &fb_ops;
+ } else {
+ devinit.version = VIS_CONS_REV;
+ devinit.width = TEXT_COLS;
+ devinit.height = TEXT_ROWS;
+ devinit.depth = 4;
+ devinit.linebytes = TEXT_COLS;
+ devinit.color_map = NULL;
+ devinit.mode = VIS_TEXT;
+ text.c_private = &text_ops;
+ }
- v86.ctl = 0;
- v86.addr = 0x10;
- v86.eax = 0x0200;
- v86.ebx = 0x0;
- v86.edx = ((0x00ff & y) << 8) + (0x00ff & x);
- v86int();
- if (_x != NULL)
- *_x = x;
- if (_y != NULL)
- *_y = y;
- /* If there is ctrl char at this position, cursor would be invisible.
- * Make it a space instead.
- */
- v86.ctl = 0;
- v86.addr = 0x10;
- v86.eax = 0x0800;
- v86.ebx = 0x0;
- v86int();
-#define isvisible(c) (((c) >= 32) && ((c) < 255))
- if (!isvisible(v86.eax & 0x00ff)) {
- write_char(' ', fg_c, bg_c);
- }
- v86.ctl = 0; /* show normal underline cursor */
- v86.addr = 0x10;
- v86.eax = 0x0100;
- v86.ecx = 0x0607;
- v86int();
+ modechg_cb(modechg_arg, &devinit);
}
-/* Scroll up the whole window by a number of rows. If rows==0,
- * clear the window. fg and bg are attributes for the new lines
- * inserted in the window.
- */
-void
-scroll_up(int rows, int fgcol, int bgcol)
+static int
+vidc_vbe_devinit(struct vis_devinit *devinit)
{
- if (rows == 0)
- rows = 25;
- v86.ctl = 0;
- v86.addr = 0x10;
- v86.eax = 0x0600 + (0x00ff & rows);
- v86.ebx = (bgcol << 12) + (fgcol << 8);
- v86.ecx = 0x0;
- v86.edx = 0x184f;
- v86int();
+ if (plat_stdout_is_framebuffer() == 0)
+ return (1);
+
+ 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;
+
+ modechg_cb = devinit->modechg_cb;
+ modechg_arg = devinit->modechg_arg;
+
+ return (0);
}
-/* Write character and attribute at cursor position. */
-void
-write_char(int c, int fgcol, int bgcol)
+static int
+vidc_text_devinit(struct vis_devinit *devinit)
{
+ if (plat_stdout_is_framebuffer())
+ return (1);
- v86.ctl = 0;
- v86.addr = 0x10;
- v86.eax = 0x0900 + (0x00ff & c);
- v86.ebx = (bgcol << 4) + fgcol;
- v86.ecx = 0x1;
- v86int();
-}
+ devinit->version = VIS_CONS_REV;
+ devinit->width = TEXT_COLS;
+ devinit->height = TEXT_ROWS;
+ devinit->depth = 4;
+ devinit->linebytes = TEXT_COLS;
+ devinit->color_map = NULL;
+ devinit->mode = VIS_TEXT;
-/**************************************************************/
-/*
- * Screen manipulation functions. They use accumulated data in
- * args[] and argc variables.
- *
- */
+ modechg_cb = devinit->modechg_cb;
+ modechg_arg = devinit->modechg_arg;
-/* Clear line from current position to end of line */
-void
-CL(int direction)
-{
- v86.ctl = 0;
- v86.addr = 0x10;
- v86.eax = 0x0600;
- v86.ebx = (bg_c << 12) + (fg_c << 8);
- if (direction == 0) { /* from cursor to end */
- v86.ecx = (cury << 8) + curx;
- v86.edx = (cury << 8) + 79;
- } else if (direction == 1) { /* from beginning to cursor */
- v86.ecx = (cury << 8) + 0;
- v86.edx = (cury << 8) + curx;
- } else if (direction == 2) { /* entire line */
- v86.ecx = (cury << 8) + 0;
- v86.edx = (cury << 8) + 79;
- }
- v86int();
- end_term();
- return;
+ return (0);
}
-/* Clear display from current position to end of screen */
-void
-CD(void)
+static int
+vidc_text_cons_clear(struct vis_consclear *ca)
{
+ uint16_t val;
+ int i;
- get_pos(&curx, &cury);
- if (curx > 0) {
- v86.ctl = 0;
- v86.addr = 0x10;
- v86.eax = 0x0600;
- v86.ebx = (bg_c << 12) + (fg_c << 8);
- v86.ecx = (cury << 8) + curx;
- v86.edx = (cury << 8) + 79;
- v86int();
- if (++cury > 24) {
- end_term();
- return;
+ val = (solaris_color_to_pc_color[ca->bg_color & 0xf] << 4) |
+ DEFAULT_FGCOLOR;
+ val = (val << 8) | ' ';
+
+ for (i = 0; i < TEXT_ROWS * TEXT_COLS; i++)
+ vgatext[i] = val;
+
+ return (0);
+}
+
+static void
+vidc_text_cons_copy(struct vis_conscopy *ma)
+{
+ uint16_t *from;
+ uint16_t *to;
+ int cnt;
+ screen_size_t chars_per_row;
+ uint16_t *to_row_start;
+ uint16_t *from_row_start;
+ screen_size_t rows_to_move;
+ uint16_t *base;
+
+ /*
+ * Sanity checks. Note that this is a last-ditch effort to avoid
+ * damage caused by broken-ness or maliciousness above.
+ */
+ if (ma->s_col < 0 || ma->s_col >= TEXT_COLS ||
+ ma->s_row < 0 || ma->s_row >= TEXT_ROWS ||
+ ma->e_col < 0 || ma->e_col >= TEXT_COLS ||
+ ma->e_row < 0 || ma->e_row >= TEXT_ROWS ||
+ ma->t_col < 0 || ma->t_col >= TEXT_COLS ||
+ ma->t_row < 0 || ma->t_row >= TEXT_ROWS ||
+ ma->s_col > ma->e_col ||
+ ma->s_row > ma->e_row)
+ return;
+
+ /*
+ * Remember we're going to copy shorts because each
+ * character/attribute pair is 16 bits.
+ */
+ chars_per_row = ma->e_col - ma->s_col + 1;
+ rows_to_move = ma->e_row - ma->s_row + 1;
+
+ /* More sanity checks. */
+ if (ma->t_row + rows_to_move > TEXT_ROWS ||
+ ma->t_col + chars_per_row > TEXT_COLS)
+ return;
+
+ base = vgatext;
+
+ to_row_start = base + ((ma->t_row * TEXT_COLS) + ma->t_col);
+ from_row_start = base + ((ma->s_row * TEXT_COLS) + ma->s_col);
+
+ if (to_row_start < from_row_start) {
+ while (rows_to_move-- > 0) {
+ to = to_row_start;
+ from = from_row_start;
+ to_row_start += TEXT_COLS;
+ from_row_start += TEXT_COLS;
+ for (cnt = chars_per_row; cnt-- > 0; )
+ *to++ = *from++;
+ }
+ } else {
+ /*
+ * Offset to the end of the region and copy backwards.
+ */
+ cnt = rows_to_move * TEXT_COLS + chars_per_row;
+ to_row_start += cnt;
+ from_row_start += cnt;
+
+ while (rows_to_move-- > 0) {
+ to_row_start -= TEXT_COLS;
+ from_row_start -= TEXT_COLS;
+ to = to_row_start;
+ from = from_row_start;
+ for (cnt = chars_per_row; cnt-- > 0; )
+ *--to = *--from;
+ }
}
- }
- v86.ctl = 0;
- v86.addr = 0x10;
- v86.eax = 0x0600;
- v86.ebx = (bg_c << 12) + (fg_c << 8);
- v86.ecx = (cury << 8) + 0;
- v86.edx = (24 << 8) + 79;
- v86int();
- end_term();
}
-/* Absolute cursor move to args[0] rows and args[1] columns
- * (the coordinates are 1-based).
+/*
+ * Binary searchable table for Unicode to CP437 conversion.
*/
-void
-CM(void)
-{
+struct unicp437 {
+ uint16_t unicode_base;
+ uint8_t cp437_base;
+ uint8_t length;
+};
- if (args[0] > 0)
- args[0]--;
- if (args[1] > 0)
- args[1]--;
- curs_move(&curx, &cury, args[1], args[0]);
- end_term();
-}
+static const struct unicp437 cp437table[] = {
+ { 0x0020, 0x20, 0x5e }, { 0x00a0, 0x20, 0x00 },
+ { 0x00a1, 0xad, 0x00 }, { 0x00a2, 0x9b, 0x00 },
+ { 0x00a3, 0x9c, 0x00 }, { 0x00a5, 0x9d, 0x00 },
+ { 0x00a7, 0x15, 0x00 }, { 0x00aa, 0xa6, 0x00 },
+ { 0x00ab, 0xae, 0x00 }, { 0x00ac, 0xaa, 0x00 },
+ { 0x00b0, 0xf8, 0x00 }, { 0x00b1, 0xf1, 0x00 },
+ { 0x00b2, 0xfd, 0x00 }, { 0x00b5, 0xe6, 0x00 },
+ { 0x00b6, 0x14, 0x00 }, { 0x00b7, 0xfa, 0x00 },
+ { 0x00ba, 0xa7, 0x00 }, { 0x00bb, 0xaf, 0x00 },
+ { 0x00bc, 0xac, 0x00 }, { 0x00bd, 0xab, 0x00 },
+ { 0x00bf, 0xa8, 0x00 }, { 0x00c4, 0x8e, 0x01 },
+ { 0x00c6, 0x92, 0x00 }, { 0x00c7, 0x80, 0x00 },
+ { 0x00c9, 0x90, 0x00 }, { 0x00d1, 0xa5, 0x00 },
+ { 0x00d6, 0x99, 0x00 }, { 0x00dc, 0x9a, 0x00 },
+ { 0x00df, 0xe1, 0x00 }, { 0x00e0, 0x85, 0x00 },
+ { 0x00e1, 0xa0, 0x00 }, { 0x00e2, 0x83, 0x00 },
+ { 0x00e4, 0x84, 0x00 }, { 0x00e5, 0x86, 0x00 },
+ { 0x00e6, 0x91, 0x00 }, { 0x00e7, 0x87, 0x00 },
+ { 0x00e8, 0x8a, 0x00 }, { 0x00e9, 0x82, 0x00 },
+ { 0x00ea, 0x88, 0x01 }, { 0x00ec, 0x8d, 0x00 },
+ { 0x00ed, 0xa1, 0x00 }, { 0x00ee, 0x8c, 0x00 },
+ { 0x00ef, 0x8b, 0x00 }, { 0x00f0, 0xeb, 0x00 },
+ { 0x00f1, 0xa4, 0x00 }, { 0x00f2, 0x95, 0x00 },
+ { 0x00f3, 0xa2, 0x00 }, { 0x00f4, 0x93, 0x00 },
+ { 0x00f6, 0x94, 0x00 }, { 0x00f7, 0xf6, 0x00 },
+ { 0x00f8, 0xed, 0x00 }, { 0x00f9, 0x97, 0x00 },
+ { 0x00fa, 0xa3, 0x00 }, { 0x00fb, 0x96, 0x00 },
+ { 0x00fc, 0x81, 0x00 }, { 0x00ff, 0x98, 0x00 },
+ { 0x0192, 0x9f, 0x00 }, { 0x0393, 0xe2, 0x00 },
+ { 0x0398, 0xe9, 0x00 }, { 0x03a3, 0xe4, 0x00 },
+ { 0x03a6, 0xe8, 0x00 }, { 0x03a9, 0xea, 0x00 },
+ { 0x03b1, 0xe0, 0x01 }, { 0x03b4, 0xeb, 0x00 },
+ { 0x03b5, 0xee, 0x00 }, { 0x03bc, 0xe6, 0x00 },
+ { 0x03c0, 0xe3, 0x00 }, { 0x03c3, 0xe5, 0x00 },
+ { 0x03c4, 0xe7, 0x00 }, { 0x03c6, 0xed, 0x00 },
+ { 0x03d5, 0xed, 0x00 }, { 0x2010, 0x2d, 0x00 },
+ { 0x2014, 0x2d, 0x00 }, { 0x2018, 0x60, 0x00 },
+ { 0x2019, 0x27, 0x00 }, { 0x201c, 0x22, 0x00 },
+ { 0x201d, 0x22, 0x00 }, { 0x2022, 0x07, 0x00 },
+ { 0x203c, 0x13, 0x00 }, { 0x207f, 0xfc, 0x00 },
+ { 0x20a7, 0x9e, 0x00 }, { 0x20ac, 0xee, 0x00 },
+ { 0x2126, 0xea, 0x00 }, { 0x2190, 0x1b, 0x00 },
+ { 0x2191, 0x18, 0x00 }, { 0x2192, 0x1a, 0x00 },
+ { 0x2193, 0x19, 0x00 }, { 0x2194, 0x1d, 0x00 },
+ { 0x2195, 0x12, 0x00 }, { 0x21a8, 0x17, 0x00 },
+ { 0x2202, 0xeb, 0x00 }, { 0x2208, 0xee, 0x00 },
+ { 0x2211, 0xe4, 0x00 }, { 0x2212, 0x2d, 0x00 },
+ { 0x2219, 0xf9, 0x00 }, { 0x221a, 0xfb, 0x00 },
+ { 0x221e, 0xec, 0x00 }, { 0x221f, 0x1c, 0x00 },
+ { 0x2229, 0xef, 0x00 }, { 0x2248, 0xf7, 0x00 },
+ { 0x2261, 0xf0, 0x00 }, { 0x2264, 0xf3, 0x00 },
+ { 0x2265, 0xf2, 0x00 }, { 0x2302, 0x7f, 0x00 },
+ { 0x2310, 0xa9, 0x00 }, { 0x2320, 0xf4, 0x00 },
+ { 0x2321, 0xf5, 0x00 }, { 0x2500, 0xc4, 0x00 },
+ { 0x2502, 0xb3, 0x00 }, { 0x250c, 0xda, 0x00 },
+ { 0x2510, 0xbf, 0x00 }, { 0x2514, 0xc0, 0x00 },
+ { 0x2518, 0xd9, 0x00 }, { 0x251c, 0xc3, 0x00 },
+ { 0x2524, 0xb4, 0x00 }, { 0x252c, 0xc2, 0x00 },
+ { 0x2534, 0xc1, 0x00 }, { 0x253c, 0xc5, 0x00 },
+ { 0x2550, 0xcd, 0x00 }, { 0x2551, 0xba, 0x00 },
+ { 0x2552, 0xd5, 0x00 }, { 0x2553, 0xd6, 0x00 },
+ { 0x2554, 0xc9, 0x00 }, { 0x2555, 0xb8, 0x00 },
+ { 0x2556, 0xb7, 0x00 }, { 0x2557, 0xbb, 0x00 },
+ { 0x2558, 0xd4, 0x00 }, { 0x2559, 0xd3, 0x00 },
+ { 0x255a, 0xc8, 0x00 }, { 0x255b, 0xbe, 0x00 },
+ { 0x255c, 0xbd, 0x00 }, { 0x255d, 0xbc, 0x00 },
+ { 0x255e, 0xc6, 0x01 }, { 0x2560, 0xcc, 0x00 },
+ { 0x2561, 0xb5, 0x00 }, { 0x2562, 0xb6, 0x00 },
+ { 0x2563, 0xb9, 0x00 }, { 0x2564, 0xd1, 0x01 },
+ { 0x2566, 0xcb, 0x00 }, { 0x2567, 0xcf, 0x00 },
+ { 0x2568, 0xd0, 0x00 }, { 0x2569, 0xca, 0x00 },
+ { 0x256a, 0xd8, 0x00 }, { 0x256b, 0xd7, 0x00 },
+ { 0x256c, 0xce, 0x00 }, { 0x2580, 0xdf, 0x00 },
+ { 0x2584, 0xdc, 0x00 }, { 0x2588, 0xdb, 0x00 },
+ { 0x258c, 0xdd, 0x00 }, { 0x2590, 0xde, 0x00 },
+ { 0x2591, 0xb0, 0x02 }, { 0x25a0, 0xfe, 0x00 },
+ { 0x25ac, 0x16, 0x00 }, { 0x25b2, 0x1e, 0x00 },
+ { 0x25ba, 0x10, 0x00 }, { 0x25bc, 0x1f, 0x00 },
+ { 0x25c4, 0x11, 0x00 }, { 0x25cb, 0x09, 0x00 },
+ { 0x25d8, 0x08, 0x00 }, { 0x25d9, 0x0a, 0x00 },
+ { 0x263a, 0x01, 0x01 }, { 0x263c, 0x0f, 0x00 },
+ { 0x2640, 0x0c, 0x00 }, { 0x2642, 0x0b, 0x00 },
+ { 0x2660, 0x06, 0x00 }, { 0x2663, 0x05, 0x00 },
+ { 0x2665, 0x03, 0x01 }, { 0x266a, 0x0d, 0x00 },
+ { 0x266c, 0x0e, 0x00 }
+};
-/* Home cursor (left top corner) */
-void
-HO(void)
+static uint8_t
+vga_get_cp437(tem_char_t c)
{
-
- argc = 1;
- args[0] = args[1] = 1;
- CM();
+ int min, mid, max;
+
+ min = 0;
+ max = (sizeof(cp437table) / sizeof(struct unicp437)) - 1;
+
+ if (c < cp437table[0].unicode_base ||
+ c > cp437table[max].unicode_base + cp437table[max].length)
+ return ('?');
+
+ while (max >= min) {
+ mid = (min + max) / 2;
+ if (c < cp437table[mid].unicode_base)
+ max = mid - 1;
+ else if (c > cp437table[mid].unicode_base +
+ cp437table[mid].length)
+ min = mid + 1;
+ else
+ return (c - cp437table[mid].unicode_base +
+ cp437table[mid].cp437_base);
+ }
+
+ return ('?');
}
-/* Clear internal state of the terminal emulation code */
-void
-end_term(void)
+static void
+vidc_text_cons_display(struct vis_consdisplay *da)
{
-
- esc = 0;
- argc = -1;
+ int i;
+ uint8_t attr;
+ tem_char_t *data;
+ struct cgatext {
+ uint8_t ch;
+ uint8_t attr;
+ } *addr;
+
+ data = (tem_char_t *)da->data;
+ attr = (solaris_color_to_pc_color[da->bg_color & 0xf] << 4) |
+ solaris_color_to_pc_color[da->fg_color & 0xf];
+ addr = (struct cgatext *) vgatext + (da->row * TEXT_COLS + da->col);
+
+ for (i = 0; i < da->width; i++) {
+ addr[i].ch = vga_get_cp437(data[i]);
+ addr[i].attr = attr;
+ }
}
-/* Gracefully exit ESC-sequence processing in case of misunderstanding */
-void
-bail_out(int c)
+static void
+vidc_text_set_cursor(screen_pos_t row, screen_pos_t col, boolean_t visible)
{
- char buf[16], *ch;
- int i;
-
- if (esc) {
- vidc_rawputchar('\033');
- if (esc != '\033')
- vidc_rawputchar(esc);
- for (i = 0; i <= argc; ++i) {
- sprintf(buf, "%d", args[i]);
- ch = buf;
- while (*ch)
- vidc_rawputchar(*ch++);
+ uint16_t addr;
+ uint8_t msl, s, e;
+
+ msl = vga_get_crtc(VGA_REG_ADDR, VGA_CRTC_MAX_S_LN) & 0x1f;
+ s = vga_get_crtc(VGA_REG_ADDR, VGA_CRTC_CSSL) & 0xC0;
+ e = vga_get_crtc(VGA_REG_ADDR, VGA_CRTC_CESL);
+
+ if (visible == B_TRUE) {
+ addr = row * TEXT_COLS + col;
+ vga_set_crtc(VGA_REG_ADDR, VGA_CRTC_CLAH, addr >> 8);
+ vga_set_crtc(VGA_REG_ADDR, VGA_CRTC_CLAL, addr & 0xff);
+ e = msl;
+ } else {
+ s |= (1<<5);
}
- }
- vidc_rawputchar(c);
- end_term();
+ vga_set_crtc(VGA_REG_ADDR, VGA_CRTC_CSSL, s);
+ vga_set_crtc(VGA_REG_ADDR, VGA_CRTC_CESL, e);
}
static void
-get_arg(int c)
+vidc_text_get_cursor(screen_pos_t *row, screen_pos_t *col)
{
+ uint16_t addr;
+
+ addr = (vga_get_crtc(VGA_REG_ADDR, VGA_CRTC_CLAH) << 8) +
+ vga_get_crtc(VGA_REG_ADDR, VGA_CRTC_CLAL);
- if (argc < 0)
- argc = 0;
- args[argc] *= 10;
- args[argc] += c - '0';
+ *row = addr / TEXT_COLS;
+ *col = addr % TEXT_COLS;
}
-/* Emulate basic capabilities of sun-color terminal */
-void
-vidc_term_emu(int c)
+static void
+vidc_cons_cursor(struct vis_conscursor *cc)
{
- static int ansi_col[] = {
- 0, 4, 2, 6, 1, 5, 3, 7,
- };
- int t;
- int i;
-
- switch (esc) {
- case 0:
- switch (c) {
- case '\033':
- esc = c;
- break;
- default:
- vidc_rawputchar(c);
- break;
+ switch (cc->action) {
+ case VIS_HIDE_CURSOR:
+ if (plat_stdout_is_framebuffer())
+ gfx_fb_display_cursor(cc);
+ else
+ vidc_text_set_cursor(cc->row, cc->col, B_FALSE);
+ break;
+ case VIS_DISPLAY_CURSOR:
+ if (plat_stdout_is_framebuffer())
+ gfx_fb_display_cursor(cc);
+ else
+ vidc_text_set_cursor(cc->row, cc->col, B_TRUE);
+ break;
+ case VIS_GET_CURSOR:
+ if (plat_stdout_is_framebuffer()) {
+ cc->row = 0;
+ cc->col = 0;
+ } else {
+ vidc_text_get_cursor(&cc->row, &cc->col);
+ }
+ break;
}
- break;
+}
- case '\033':
+static uint8_t
+c24_to_vga(uint8_t c, uint8_t mask)
+{
switch (c) {
- case '[':
- esc = c;
- args[0] = 0;
- argc = -1;
- break;
+ case 0x40:
+ return (0x15 & mask);
+ case 0x80:
+ return (0x2A & mask);
+ case 0xFF:
+ return (c & mask);
default:
- bail_out(c);
- break;
+ return (0);
}
- break;
+}
- case '[':
- switch (c) {
- case ';':
- if (argc < 0) /* XXX */
- argc = 0;
- else if (argc + 1 >= MAXARGS)
- bail_out(c);
- else
- args[++argc] = 0;
- break;
- case 'A': /* UP = \E[%dA */
- if (argc == 0) {
- int 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) {
- int 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) {
- int 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]);
+static int
+vidc_vbe_cons_put_cmap(struct vis_cmap *cm)
+{
+ int i, bits, rc = 0;
+ struct paletteentry pe;
+
+ bits = 1; /* get DAC palette width */
+ rc = biosvbe_palette_format(&bits);
+ if (rc != VBE_SUCCESS)
+ return (rc);
+
+ bits = 0xFF >> (8 - (bits >> 8));
+ pe.Alignment = 0;
+ for (i = 0; i < cm->count; i++) {
+ pe.Red = c24_to_vga(cm->red[i], bits);
+ pe.Green = c24_to_vga(cm->green[i], bits);
+ pe.Blue = c24_to_vga(cm->blue[i], bits);
+ rc = vbe_set_palette(&pe,
+ solaris_color_to_pc_color[cm->index + i]);
+ if (rc != 0)
break;
- default:
- bail_out(c);
- }
- 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 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;
- }
- }
- end_term();
- break;
- default:
- if (isdigit(c))
- get_arg(c);
- else
- bail_out(c);
- break;
}
- break;
+ return (rc);
+}
- default:
- bail_out(c);
- break;
- }
+static int
+vidc_text_cons_put_cmap(struct vis_cmap *cm __unused)
+{
+ return (1);
+}
+
+static int
+vidc_ioctl(struct console *cp, int cmd, void *data)
+{
+ struct visual_ops *ops = cp->c_private;
+
+ switch (cmd) {
+ case VIS_GETIDENTIFIER:
+ memmove(data, ops->ident, sizeof (struct vis_identifier));
+ break;
+ case VIS_DEVINIT:
+ return (ops->devinit(data));
+ case VIS_CONSCLEAR:
+ return (ops->cons_clear(data));
+ case VIS_CONSCOPY:
+ ops->cons_copy(data);
+ break;
+ case VIS_CONSDISPLAY:
+ ops->cons_display(data);
+ break;
+ case VIS_CONSCURSOR:
+ ops->cons_cursor(data);
+ break;
+ case VIS_PUTCMAP:
+ ops->cons_put_cmap(data);
+ break;
+ case VIS_GETCMAP:
+ default:
+ return (EINVAL);
+ }
+ return (0);
}
-#endif
static void
-vidc_putchar(struct console *cp, int c)
+vidc_probe(struct console *cp)
{
-#ifdef TERM_EMU
- vidc_term_emu(c);
-#else
- vidc_rawputchar(c);
+
+ /* look for a keyboard */
+#if KEYBOARD_PROBE
+ if (probe_keyboard())
#endif
+ {
+ cp->c_flags |= C_PRESENTIN;
+ }
+
+ /* XXX for now, always assume we can do BIOS screen output */
+ cp->c_flags |= C_PRESENTOUT;
+ vbe_init();
+ tem = NULL;
}
static int
-vidc_getchar(struct console *cp)
+vidc_init(struct console *cp, int arg)
{
- int i, c;
+ int i, rc;
+
+ if (vidc_started && arg == 0)
+ return (0);
+
+ vidc_started = 1;
+ gfx_framework_init(&fb_ops);
+
+ /*
+ * Check Miscellaneous Output Register (Read at 3CCh, Write at 3C2h)
+ * for bit 1 (Input/Output Address Select), which means
+ * color/graphics adapter.
+ */
+ if (vga_get_reg(VGA_REG_ADDR, VGA_MISC_R) & VGA_MISC_IOA_SEL)
+ vgatext = (uint16_t *) PTOV(VGA_MEM_ADDR + VGA_COLOR_BASE);
+ else
+ vgatext = (uint16_t *) PTOV(VGA_MEM_ADDR + VGA_MONO_BASE);
+
+ /* set 16bit colors */
+ i = vga_get_atr(VGA_REG_ADDR, VGA_ATR_MODE);
+ i &= ~VGA_ATR_MODE_BLINK;
+ i &= ~VGA_ATR_MODE_9WIDE;
+ vga_set_atr(VGA_REG_ADDR, VGA_ATR_MODE, i);
+
+ plat_tem_hide_prom_cursor();
+
+ memset(keybuf, 0, KEYBUFSZ);
+
+ /* default to text mode */
+ cp->c_private = &text_ops;
+
+ if (vbe_available()) {
+ rc = vbe_default_mode();
+ /* if rc is not legal VBE mode, use text mode */
+ if (VBE_VALID_MODE(rc)) {
+ if (vbe_set_mode(rc) == 0)
+ cp->c_private = &fb_ops;
+ else
+ bios_set_text_mode(VGA_TEXT_MODE);
+ }
+ }
- for (i = 0; i < KEYBUFSZ; i++) {
- if (keybuf[i] != 0) {
- c = keybuf[i];
- keybuf[i] = 0;
- return (c);
+ rc = tem_info_init(cp);
+
+ if (rc != 0) {
+ bios_set_text_mode(3);
+ cp->c_private = &text_ops;
+ rc = tem_info_init(cp); /* try again */
+ }
+ if (rc == 0 && tem == NULL) {
+ tem = tem_init();
+ if (tem != NULL)
+ tem_activate(tem, B_TRUE);
}
- }
- if (vidc_ischar(cp)) {
+ for (i = 0; i < 10 && vidc_ischar(cp); i++)
+ (void)vidc_getchar(cp);
+
+ return (0); /* XXX reinit? */
+}
+
+static void
+vidc_biosputchar(int c)
+{
v86.ctl = 0;
- v86.addr = 0x16;
- v86.eax = 0x0;
+ v86.addr = 0x10;
+ v86.eax = 0xe00 | (c & 0xff);
+ v86.ebx = 0x7;
v86int();
- if ((v86.eax & 0xff) != 0) {
- return (v86.eax & 0xff);
+}
+
+static void
+vidc_putchar(struct console *cp __unused, int c)
+{
+ uint8_t buf = c;
+
+ /* make sure we have some console output, support for panic() */
+ if (tem == NULL)
+ vidc_biosputchar(c);
+ else
+ tem_write(tem, &buf, sizeof (buf));
+}
+
+static int
+vidc_getchar(struct console *cp)
+{
+ int i, c;
+
+ for (i = 0; i < KEYBUFSZ; i++) {
+ if (keybuf[i] != 0) {
+ c = keybuf[i];
+ keybuf[i] = 0;
+ return (c);
+ }
}
- /* extended keys */
- switch (v86.eax & 0xff00) {
- case 0x4800: /* up */
- keybuf[0] = '[';
- keybuf[1] = 'A';
- return (0x1b); /* esc */
- case 0x4b00: /* left */
- keybuf[0] = '[';
- keybuf[1] = 'D';
- return (0x1b); /* esc */
- case 0x4d00: /* right */
- keybuf[0] = '[';
- keybuf[1] = 'C';
- return (0x1b); /* esc */
- case 0x5000: /* down */
- keybuf[0] = '[';
- keybuf[1] = 'B';
- return (0x1b); /* esc */
- default:
+ if (vidc_ischar(cp)) {
+ v86.ctl = 0;
+ v86.addr = 0x16;
+ v86.eax = 0x0;
+ v86int();
+ if ((v86.eax & 0xff) != 0) {
+ return (v86.eax & 0xff);
+ }
+
+ /* extended keys */
+ switch (v86.eax & 0xff00) {
+ case 0x4800: /* up */
+ keybuf[0] = '[';
+ keybuf[1] = 'A';
+ return (0x1b); /* esc */
+ case 0x4b00: /* left */
+ keybuf[0] = '[';
+ keybuf[1] = 'D';
+ return (0x1b); /* esc */
+ case 0x4d00: /* right */
+ keybuf[0] = '[';
+ keybuf[1] = 'C';
+ return (0x1b); /* esc */
+ case 0x5000: /* down */
+ keybuf[0] = '[';
+ keybuf[1] = 'B';
+ return (0x1b); /* esc */
+ default:
+ return (-1);
+ }
+ } else {
return (-1);
}
- } else {
- return (-1);
- }
}
static int
-vidc_ischar(struct console *cp)
+vidc_ischar(struct console *cp __unused)
{
- int i;
+ int i;
- for (i = 0; i < KEYBUFSZ; i++) {
- if (keybuf[i] != 0) {
- return (1);
+ for (i = 0; i < KEYBUFSZ; i++) {
+ if (keybuf[i] != 0) {
+ return (1);
+ }
}
- }
- v86.ctl = V86_FLAGS;
- v86.addr = 0x16;
- v86.eax = 0x100;
- v86int();
- return (!V86_ZR(v86.efl));
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x16;
+ v86.eax = 0x100;
+ v86int();
+ return (!V86_ZR(v86.efl));
}
#if KEYBOARD_PROBE
@@ -654,10 +791,10 @@ vidc_ischar(struct console *cp)
#define IO_KBD 0x060 /* 8042 Keyboard */
/* selected defines from kbdio.h */
-#define KBD_STATUS_PORT 4 /* status port, read */
-#define KBD_DATA_PORT 0 /* data port, read/write
+#define KBD_STATUS_PORT 4 /* status port, read */
+#define KBD_DATA_PORT 0 /* data port, read/write
* also used as keyboard command
- * and mouse command port
+ * and mouse command port
*/
#define KBDC_ECHO 0x00ee
#define KBDS_ANY_BUFFER_FULL 0x0001
@@ -668,13 +805,13 @@ vidc_ischar(struct console *cp)
static void
delay7(void)
{
- /*
- * I know this is broken, but no timer is available yet at this stage...
- * See also comments in `delay1ms()'.
- */
- inb(IO_DUMMY); inb(IO_DUMMY);
- inb(IO_DUMMY); inb(IO_DUMMY);
- inb(IO_DUMMY); inb(IO_DUMMY);
+ /*
+ * I know this is broken, but no timer is available yet at this stage...
+ * See also comments in `delay1ms()'.
+ */
+ inb(IO_DUMMY); inb(IO_DUMMY);
+ inb(IO_DUMMY); inb(IO_DUMMY);
+ inb(IO_DUMMY); inb(IO_DUMMY);
}
/*
@@ -689,12 +826,12 @@ delay7(void)
static void
delay1ms(void)
{
- int i = 800;
- while (--i >= 0)
- (void)inb(0x84);
+ int i = 800;
+ while (--i >= 0)
+ (void)inb(0x84);
}
-/*
+/*
* We use the presence/absence of a keyboard to determine whether the internal
* console can be used for input.
*
@@ -705,55 +842,57 @@ delay1ms(void)
static int
probe_keyboard(void)
{
- int retry = PROBE_MAXRETRY;
- int wait;
- int i;
-
- while (--retry >= 0) {
- /* flush any noise */
- while (inb(IO_KBD + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL) {
- delay7();
- inb(IO_KBD + KBD_DATA_PORT);
- delay1ms();
- }
-
- /* wait until the controller can accept a command */
- for (wait = PROBE_MAXWAIT; wait > 0; --wait) {
- if (((i = inb(IO_KBD + KBD_STATUS_PORT))
- & (KBDS_INPUT_BUFFER_FULL | KBDS_ANY_BUFFER_FULL)) == 0)
- break;
- if (i & KBDS_ANY_BUFFER_FULL) {
- delay7();
- inb(IO_KBD + KBD_DATA_PORT);
- }
- delay1ms();
- }
- if (wait <= 0)
- continue;
-
- /* send the ECHO command */
- outb(IO_KBD + KBD_DATA_PORT, KBDC_ECHO);
+ int retry = PROBE_MAXRETRY;
+ int wait;
+ int i;
+
+ while (--retry >= 0) {
+ /* flush any noise */
+ while (inb(IO_KBD + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL) {
+ delay7();
+ inb(IO_KBD + KBD_DATA_PORT);
+ delay1ms();
+ }
- /* wait for a response */
- for (wait = PROBE_MAXWAIT; wait > 0; --wait) {
- if (inb(IO_KBD + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL)
- break;
- delay1ms();
- }
- if (wait <= 0)
- continue;
+ /* wait until the controller can accept a command */
+ for (wait = PROBE_MAXWAIT; wait > 0; --wait) {
+ if (((i = inb(IO_KBD + KBD_STATUS_PORT)) &
+ (KBDS_INPUT_BUFFER_FULL | KBDS_ANY_BUFFER_FULL))
+ == 0)
+ break;
+ if (i & KBDS_ANY_BUFFER_FULL) {
+ delay7();
+ inb(IO_KBD + KBD_DATA_PORT);
+ }
+ delay1ms();
+ }
+ if (wait <= 0)
+ continue;
+
+ /* send the ECHO command */
+ outb(IO_KBD + KBD_DATA_PORT, KBDC_ECHO);
+
+ /* wait for a response */
+ for (wait = PROBE_MAXWAIT; wait > 0; --wait) {
+ if (inb(IO_KBD + KBD_STATUS_PORT) &
+ KBDS_ANY_BUFFER_FULL)
+ break;
+ delay1ms();
+ }
+ if (wait <= 0)
+ continue;
- delay7();
- i = inb(IO_KBD + KBD_DATA_PORT);
+ delay7();
+ i = inb(IO_KBD + KBD_DATA_PORT);
#ifdef PROBE_KBD_BEBUG
- printf("probe_keyboard: got 0x%x.\n", i);
+ printf("probe_keyboard: got 0x%x.\n", i);
#endif
- if (i == KBD_ECHO) {
- /* got the right answer */
- return (1);
+ if (i == KBD_ECHO) {
+ /* got the right answer */
+ return (1);
+ }
}
- }
- return (0);
+ return (0);
}
#endif /* KEYBOARD_PROBE */
diff --git a/usr/src/boot/sys/boot/i386/loader/Makefile b/usr/src/boot/sys/boot/i386/loader/Makefile
index a6ef330289..84eb91bfde 100644
--- a/usr/src/boot/sys/boot/i386/loader/Makefile
+++ b/usr/src/boot/sys/boot/i386/loader/Makefile
@@ -16,6 +16,7 @@
include $(SRC)/Makefile.master
include $(SRC)/boot/Makefile.version
+include $(SRC)/boot/sys/boot/Makefile.inc
CFLAGS= -Os -fno-reorder-functions
CPPFLAGS= -D_STANDALONE -nostdinc -I../../../../include -I../../..
@@ -50,7 +51,6 @@ all: ${LOADER} loader.help
install: all $(ROOTBOOTLOADER)
PROG= ${LOADER}.sym
-INTERNALPROG=
# architecture-specific loader code
SRCS= main.c conf.c vers.c chain.c
@@ -66,6 +66,7 @@ SRCS += boot.c commands.c console.c devopen.c interp.c
SRCS += interp_backslash.c interp_parse.c ls.c misc.c
SRCS += module.c panic.c linenoise.c multiboot2.c
SRCS += zfs_cmd.c
+SRCS += font.c $(FONT).c list.c tem.c
SRCS += load_elf32.c load_elf32_obj.c reloc_elf32.c
SRCS += load_elf64.c load_elf64_obj.c reloc_elf64.c
@@ -89,6 +90,7 @@ CPPFLAGS += -I../../common
CPPFLAGS += -I.
CLEANFILES= vers.c ${LOADER} ${LOADER}.sym ${LOADER}.bin loader.help
+CLEANFILES += $(FONT).c
CFLAGS += -Wall
LDFLAGS= -static -Ttext 0x0
@@ -166,6 +168,15 @@ install: all $(ROOT_BOOT_DEFAULTS) $(ROOT_BOOT_FORTH) \
%.o: ../../common/linenoise/%.c
$(COMPILE.c) -o $@ $<
+%.o: $(SRC)/common/list/%.c
+ $(COMPILE.c) -DNDEBUG $<
+
+%.o: $(SRC)/common/font/%.c
+ $(COMPILE.c) $<
+
+$(FONT).c: $(FONT_DIR)/$(FONT_SRC)
+ $(VTFONTCVT) -f compressed-source -o $@ $(FONT_DIR)/$(FONT_SRC)
+
$(ROOT_BOOT)/%: ../../forth/%
$(INS.file)
diff --git a/usr/src/boot/sys/boot/i386/loader/chain.c b/usr/src/boot/sys/boot/i386/loader/chain.c
index 04658076bb..2f32a9adf0 100644
--- a/usr/src/boot/sys/boot/i386/loader/chain.c
+++ b/usr/src/boot/sys/boot/i386/loader/chain.c
@@ -27,6 +27,7 @@
#include <sys/diskmbr.h>
#include "bootstrap.h"
+#include "libi386/vbe.h"
#include "libi386/libi386.h"
#include "btxv86.h"
@@ -96,6 +97,7 @@ command_chain(int argc, char *argv[])
return (CMD_ERROR);
}
+ bios_set_text_mode(3);
relocater_data[0].src = mem;
relocater_data[0].dest = 0x7C00;
relocater_data[0].size = size;
diff --git a/usr/src/boot/sys/boot/i386/loader/main.c b/usr/src/boot/sys/boot/i386/loader/main.c
index cd605f1002..6f96c6a757 100644
--- a/usr/src/boot/sys/boot/i386/loader/main.c
+++ b/usr/src/boot/sys/boot/i386/loader/main.c
@@ -160,6 +160,7 @@ main(void)
for (i = 0; devsw[i] != NULL; i++)
if (devsw[i]->dv_init != NULL)
(devsw[i]->dv_init)();
+
printf("BIOS %dkB/%dkB available memory\n", bios_basemem / 1024, bios_extmem / 1024);
if (initial_bootinfo != NULL) {
initial_bootinfo->bi_basemem = bios_basemem / 1024;
@@ -177,9 +178,8 @@ main(void)
printf("\n%s", bootprog_info);
- extract_currdev(); /* set $currdev and $loaddev */
- setenv("LINES", "24", 1); /* optional */
- setenv("COLUMNS", "80", 1); /* optional */
+ extract_currdev(); /* set $currdev and $loaddev */
+ autoload_font(); /* Set up the font list for console. */
bi_isadir();
bios_getsmap();
diff --git a/usr/src/boot/sys/boot/libficl/Makefile.com b/usr/src/boot/sys/boot/libficl/Makefile.com
index 7ea9c354fe..4d58aa5755 100644
--- a/usr/src/boot/sys/boot/libficl/Makefile.com
+++ b/usr/src/boot/sys/boot/libficl/Makefile.com
@@ -16,10 +16,14 @@
CC= $(GNUC_ROOT)/bin/gcc
FICLDIR= $(SRC)/common/ficl
+PNGLITE= $(SRC)/common/pnglite
CPPFLAGS= -nostdinc -D_STANDALONE -I. -I.. -I../../../../include
CPPFLAGS += -I../../../../lib/libstand
-CPPFLAGS += -I../../.. -I$(FICLDIR) -I../../common
+CPPFLAGS += -I../../.. -I$(FICLDIR) -I../../common -I$(PNGLITE)
+
+# For multiboot2.h, must be last, to avoid conflicts
+CPPFLAGS += -I$(SRC)/uts/common
CFLAGS= -Os -fPIC -Wall -ffreestanding -mno-mmx -mno-3dnow -mno-sse
CFLAGS += -mno-sse2 -mno-sse3 -msoft-float -std=gnu99
diff --git a/usr/src/boot/sys/boot/ofw/common/main.c b/usr/src/boot/sys/boot/ofw/common/main.c
index 0f6ed132ea..a927203a76 100644
--- a/usr/src/boot/sys/boot/ofw/common/main.c
+++ b/usr/src/boot/sys/boot/ofw/common/main.c
@@ -147,7 +147,7 @@ main(int (*openfirm)(void *))
ofw_setcurrdev, env_nounset);
env_setenv("loaddev", EV_VOLATILE, bootpath, env_noset,
env_nounset);
- setenv("LINES", "24", 1); /* optional */
+ setenv("screen-#rows", "24", 1); /* optional */
archsw.arch_getdev = ofw_getdev;
archsw.arch_copyin = ofw_copyin;
diff --git a/usr/src/boot/sys/boot/uboot/common/main.c b/usr/src/boot/sys/boot/uboot/common/main.c
index 3297aa4721..704a5a8708 100644
--- a/usr/src/boot/sys/boot/uboot/common/main.c
+++ b/usr/src/boot/sys/boot/uboot/common/main.c
@@ -482,7 +482,7 @@ main(void)
env_setenv("loaddev", EV_VOLATILE, ldev, env_noset, env_nounset);
printf("Booting from %s\n", ldev);
- setenv("LINES", "24", 1); /* optional */
+ setenv("screen-#rows", "24", 1); /* optional */
setenv("prompt", "loader>", 1);
archsw.arch_loadaddr = uboot_loadaddr;
diff --git a/usr/src/boot/sys/boot/userboot/userboot/main.c b/usr/src/boot/sys/boot/userboot/userboot/main.c
index 3a53ae2b94..cb8d87ec59 100644
--- a/usr/src/boot/sys/boot/userboot/userboot/main.c
+++ b/usr/src/boot/sys/boot/userboot/userboot/main.c
@@ -98,7 +98,7 @@ loader_main(struct loader_callbacks *cb, void *arg, int version, int ndisks)
printf("Memory: %ld k\n", memsize() / 1024);
#endif
- setenv("LINES", "24", 1); /* optional */
+ setenv("screen-#rows", "24", 1); /* optional */
/*
* Set custom environment variables
diff --git a/usr/src/boot/sys/cddl/boot/zfs/zfsimpl.h b/usr/src/boot/sys/cddl/boot/zfs/zfsimpl.h
index 8cd5cf8f2b..ed82362221 100644
--- a/usr/src/boot/sys/cddl/boot/zfs/zfsimpl.h
+++ b/usr/src/boot/sys/cddl/boot/zfs/zfsimpl.h
@@ -63,8 +63,6 @@
#define _NOTE(s)
-typedef enum { B_FALSE, B_TRUE } boolean_t;
-
/* CRC64 table */
#define ZFS_CRC64_POLY 0xC96C5795D7870F42ULL /* ECMA-182, reflected form */
@@ -1243,10 +1241,10 @@ typedef struct mzap_phys {
* 1<<FZAP_BLOCK_SHIFT byte blocks. The layout looks like one of:
*
* ptrtbl fits in first block:
- * [zap_phys_t zap_ptrtbl_shift < 6] [zap_leaf_t] ...
+ * [zap_phys_t zap_ptrtbl_shift < 6] [zap_leaf_t] ...
*
* ptrtbl too big for first block:
- * [zap_phys_t zap_ptrtbl_shift >= 6] [zap_leaf_t] [ptrtbl] ...
+ * [zap_phys_t zap_ptrtbl_shift >= 6] [zap_leaf_t] [ptrtbl] ...
*
*/
@@ -1396,7 +1394,7 @@ typedef struct zap_leaf_phys {
typedef union zap_leaf_chunk {
struct zap_leaf_entry {
- uint8_t le_type; /* always ZAP_CHUNK_ENTRY */
+ uint8_t le_type; /* always ZAP_CHUNK_ENTRY */
uint8_t le_value_intlen; /* size of ints */
uint16_t le_next; /* next entry in hash chain */
uint16_t le_name_chunk; /* first chunk of the name */
diff --git a/usr/src/boot/sys/sys/font.h b/usr/src/boot/sys/sys/font.h
new file mode 100644
index 0000000000..4ff7160b52
--- /dev/null
+++ b/usr/src/boot/sys/sys/font.h
@@ -0,0 +1,137 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_FONT_H
+#define _SYS_FONT_H
+
+#include <sys/queue.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum vfnt_map {
+ VFNT_MAP_NORMAL = 0, /* Normal font. */
+ VFNT_MAP_NORMAL_RH, /* Normal font right hand. */
+ VFNT_MAP_BOLD, /* Bold font. */
+ VFNT_MAP_BOLD_RH, /* Bold font right hand. */
+ VFNT_MAPS /* Number of maps. */
+};
+
+/*
+ * If the custom console font was loaded, pass it for kernel as an module.
+ * We do not just load the font file, as the font file needs to be processed,
+ * and the early boot has very little resources. So we just set up the
+ * needed structures and make an copy of the byte arrays.
+ *
+ * Note we can not copy the structures one to one due to the pointer size,
+ * so we record the data by using fixed size structure.
+ */
+struct font_info {
+ int32_t fi_checksum;
+ uint32_t fi_width;
+ uint32_t fi_height;
+ uint32_t fi_bitmap_size;
+ uint32_t fi_map_count[VFNT_MAPS];
+};
+
+struct font_map {
+ uint32_t font_src; /* Source glyph. */
+ uint16_t font_dst; /* Target glyph. */
+ uint16_t font_len; /* The number of glyphs in sequence. */
+};
+
+/* Any unknown glyph is mapped as first (offset 0) glyph in bitmap. */
+struct font {
+ struct font_map *vf_map[VFNT_MAPS]; /* Mapping tables. */
+ uint8_t *vf_bytes; /* Font bitmap data. */
+ uint32_t vf_width; /* Glyph width. */
+ uint32_t vf_height; /* Glyph height. */
+ uint32_t vf_map_count[VFNT_MAPS]; /* Entries in map */
+};
+
+typedef struct bitmap_data {
+ uint32_t width;
+ uint32_t height;
+ uint32_t compressed_size;
+ uint32_t uncompressed_size;
+ uint8_t *compressed_data;
+ struct font *font;
+} bitmap_data_t;
+
+typedef enum {
+ FONT_AUTO,
+ FONT_MANUAL,
+ FONT_BOOT
+} FONT_FLAGS;
+
+struct fontlist {
+ char *font_name;
+ FONT_FLAGS font_flags;
+ bitmap_data_t *font_data;
+ bitmap_data_t *(*font_load)(char *);
+ STAILQ_ENTRY(fontlist) font_next;
+};
+
+#define FONT_HEADER_MAGIC "VFNT0002"
+struct font_header {
+ uint8_t fh_magic[8];
+ uint8_t fh_width;
+ uint8_t fh_height;
+ uint16_t fh_pad;
+ uint32_t fh_glyph_count;
+ uint32_t fh_map_count[4];
+} __attribute__((__packed__));
+
+typedef STAILQ_HEAD(font_list, fontlist) font_list_t;
+extern font_list_t fonts;
+
+/*
+ * Built in fonts. We are using Gallant as default on sparc to keep
+ * smooth transition from prom and 8x16 on x86, for vga text mode.
+ */
+#ifdef sparc
+#define DEFAULT_FONT_DATA font_data_12x22
+extern bitmap_data_t font_data_12x22;
+#else
+#define DEFAULT_FONT_DATA font_data_8x16
+extern bitmap_data_t font_data_8x16;
+#endif
+#define BORDER_PIXELS 10 /* space from screen border */
+
+bitmap_data_t *set_font(short *, short *, short, short);
+const uint8_t *font_lookup(const struct font *, uint32_t);
+void font_bit_to_pix4(struct font *, uint8_t *, uint32_t, uint8_t, uint8_t);
+void font_bit_to_pix8(struct font *, uint8_t *, uint32_t, uint8_t, uint8_t);
+void font_bit_to_pix16(struct font *, uint16_t *, uint32_t, uint16_t, uint16_t);
+void font_bit_to_pix24(struct font *, uint8_t *, uint32_t, uint32_t, uint32_t);
+void font_bit_to_pix32(struct font *, uint32_t *, uint32_t, uint32_t, uint32_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_SYS_FONT_H */
diff --git a/usr/src/boot/sys/sys/sysmacros.h b/usr/src/boot/sys/sys/sysmacros.h
new file mode 100644
index 0000000000..8f7989ae1e
--- /dev/null
+++ b/usr/src/boot/sys/sys/sysmacros.h
@@ -0,0 +1,6 @@
+
+/*
+ * Compatibility header for illumos.
+ */
+#include <stand.h>
+#include <sys/param.h>
diff --git a/usr/src/boot/sys/sys/tem.h b/usr/src/boot/sys/sys/tem.h
new file mode 100644
index 0000000000..fef3277c50
--- /dev/null
+++ b/usr/src/boot/sys/sys/tem.h
@@ -0,0 +1,74 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */
+/* All Rights Reserved */
+
+#ifndef _SYS_TEM_H
+#define _SYS_TEM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <sys/visual_io.h>
+
+typedef uint8_t text_color_t;
+
+typedef struct __tem_modechg_cb_arg *tem_modechg_cb_arg_t;
+typedef void (*tem_modechg_cb_t) (tem_modechg_cb_arg_t arg);
+typedef struct __tem_vt_state *tem_vt_state_t;
+
+/*
+ * tems_* fuctions mean that they just operate on the common soft state
+ * (tem_state_t), and tem_* functions mean that they operate on the
+ * per-tem structure (tem_vt_state).
+ */
+int tems_cls(struct vis_consclear *);
+void tems_display(struct vis_consdisplay *);
+void tems_copy(struct vis_conscopy *);
+void tems_cursor(struct vis_conscursor *);
+
+int tem_initialized(tem_vt_state_t);
+
+tem_vt_state_t tem_init(void);
+
+int tem_info_init(struct console *);
+void tem_write(tem_vt_state_t, uint8_t *, ssize_t);
+void tem_get_size(uint16_t *, uint16_t *, uint16_t *, uint16_t *);
+void tem_save_state(void);
+void tem_register_modechg_cb(tem_modechg_cb_t, tem_modechg_cb_arg_t);
+void tem_activate(tem_vt_state_t, boolean_t);
+void tem_switch(tem_vt_state_t, tem_vt_state_t);
+void tem_get_colors(tem_vt_state_t, text_color_t *, text_color_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_TEM_H */
diff --git a/usr/src/boot/sys/sys/tem_impl.h b/usr/src/boot/sys/sys/tem_impl.h
new file mode 100644
index 0000000000..ea4d0f2b3b
--- /dev/null
+++ b/usr/src/boot/sys/sys/tem_impl.h
@@ -0,0 +1,286 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */
+/* All Rights Reserved */
+
+#ifndef _SYS_TEM_H
+#define _SYS_TEM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <sys/visual_io.h>
+#include <sys/font.h>
+#include <sys/list.h>
+#include <sys/tem.h>
+#include <bootstrap.h>
+#include <stdbool.h>
+
+/*
+ * Definitions for ANSI x3.64 terminal control language parser.
+ * With UTF-8 support we use 32-bit value for Unicode codepoints.
+ *
+ * However, as we only need 21 bits for unicode char, we will use the
+ * rest of the bits for attributes, so we can save memory and
+ * have combined attribute+char in screen buffer. This will also allow us
+ * to keep better track about attributes and apply other optimizations.
+ *
+ * Bits Meaning
+ * 0-20 char
+ * 21-31 attributes
+ */
+
+typedef uint32_t tem_char_t; /* 32bit char to support UTF-8 */
+#define TEM_ATTR_MASK 0x7FF
+#define TEM_CHAR(c) ((c) & 0x1fffff)
+#define TEM_CHAR_ATTR(c) (((c) >> 21) & TEM_ATTR_MASK)
+#define TEM_ATTR(c) (((c) & TEM_ATTR_MASK) << 21)
+
+#define TEM_MAXPARAMS 5 /* maximum number of ANSI paramters */
+#define TEM_MAXTAB 40 /* maximum number of tab stops */
+#define TEM_MAXFKEY 30 /* max length of function key with <ESC>Q */
+#define MAX_TEM 2 /* max number of loadable terminal emulators */
+
+#define TEM_SCROLL_UP 0
+#define TEM_SCROLL_DOWN 1
+#define TEM_SHIFT_LEFT 0
+#define TEM_SHIFT_RIGHT 1
+
+/* Attributes 0-0x7ff */
+#define TEM_ATTR_NORMAL 0x0000
+#define TEM_ATTR_REVERSE 0x0001
+#define TEM_ATTR_BOLD 0x0002
+#define TEM_ATTR_BLINK 0x0004
+#define TEM_ATTR_UNDERLINE 0x0008
+#define TEM_ATTR_SCREEN_REVERSE 0x0010
+#define TEM_ATTR_BRIGHT_FG 0x0020
+#define TEM_ATTR_BRIGHT_BG 0x0040
+#define TEM_ATTR_TRANSPARENT 0x0080
+#define TEM_ATTR_IMAGE 0x0100
+
+#define ANSI_COLOR_BLACK 0
+#define ANSI_COLOR_RED 1
+#define ANSI_COLOR_GREEN 2
+#define ANSI_COLOR_YELLOW 3
+#define ANSI_COLOR_BLUE 4
+#define ANSI_COLOR_MAGENTA 5
+#define ANSI_COLOR_CYAN 6
+#define ANSI_COLOR_WHITE 7
+
+#define TEM_TEXT_WHITE 0
+#define TEM_TEXT_BLACK 1
+#define TEM_TEXT_BLACK24_RED 0x00
+#define TEM_TEXT_BLACK24_GREEN 0x00
+#define TEM_TEXT_BLACK24_BLUE 0x00
+#define TEM_TEXT_WHITE24_RED 0xff
+#define TEM_TEXT_WHITE24_GREEN 0xff
+#define TEM_TEXT_WHITE24_BLUE 0xff
+
+#define A_STATE_START 0
+#define A_STATE_ESC 1
+#define A_STATE_CSI 2
+#define A_STATE_CSI_QMARK 3
+#define A_STATE_CSI_EQUAL 4
+
+/*
+ * Default number of rows and columns
+ */
+#define TEM_DEFAULT_ROWS 25
+#define TEM_DEFAULT_COLS 80
+
+/*
+ * Default foreground/background color
+ */
+
+#define DEFAULT_ANSI_FOREGROUND ANSI_COLOR_BLACK
+#define DEFAULT_ANSI_BACKGROUND ANSI_COLOR_WHITE
+
+
+#define BUF_LEN 160 /* Two lines of data can be processed at a time */
+
+typedef uint8_t text_color_t;
+typedef uint16_t text_attr_t;
+
+typedef struct tem_color {
+ text_color_t fg_color;
+ text_color_t bg_color;
+ text_attr_t a_flags;
+} tem_color_t;
+
+struct tem_pix_pos {
+ screen_pos_t x;
+ screen_pos_t y;
+};
+
+struct tem_char_pos {
+ screen_pos_t col;
+ screen_pos_t row;
+};
+
+struct tem_size {
+ screen_size_t width;
+ screen_size_t height;
+};
+
+typedef struct {
+ uint8_t red[16];
+ uint8_t green[16];
+ uint8_t blue[16];
+} text_cmap_t;
+
+/* Combined color and 32bit tem char */
+typedef struct term_char {
+ text_color_t tc_fg_color;
+ text_color_t tc_bg_color;
+ tem_char_t tc_char;
+} term_char_t;
+
+/* Color translation tables. */
+extern const uint8_t dim_xlate[8];
+extern const uint8_t brt_xlate[8];
+extern const uint8_t solaris_color_to_pc_color[16];
+extern const text_cmap_t cmap4_to_24;
+
+/*
+ * State structure for each virtual terminal emulator
+ */
+struct tem_vt_state {
+ uint8_t tvs_fbmode; /* framebuffer mode */
+ text_attr_t tvs_flags; /* flags for this x3.64 terminal */
+ int tvs_state; /* state in output esc seq processing */
+ bool tvs_gotparam; /* does output esc seq have a param */
+
+ int tvs_curparam; /* current param # of output esc seq */
+ int tvs_paramval; /* value of current param */
+ int tvs_params[TEM_MAXPARAMS]; /* parameters of output esc seq */
+ screen_pos_t tvs_tabs[TEM_MAXTAB]; /* tab stops */
+ int tvs_ntabs; /* number of tabs used */
+ int tvs_nscroll; /* number of lines to scroll */
+
+ struct tem_char_pos tvs_s_cursor; /* start cursor position */
+ struct tem_char_pos tvs_c_cursor; /* current cursor position */
+ struct tem_char_pos tvs_r_cursor; /* remembered cursor position */
+
+ term_char_t *tvs_outbuf; /* place to keep incomplete lines */
+ int tvs_outindex; /* index into a_outbuf */
+ void *tvs_pix_data; /* pointer to tmp bitmap area */
+ int tvs_pix_data_size;
+ text_color_t tvs_fg_color;
+ text_color_t tvs_bg_color;
+ int tvs_first_line; /* kernel console output begins */
+
+ term_char_t *tvs_screen_buf; /* whole screen buffer */
+ unsigned tvs_utf8_left; /* UTF-8 code points */
+ tem_char_t tvs_utf8_partial; /* UTF-8 char being completed */
+
+ bool tvs_isactive;
+ bool tvs_initialized; /* initialization flag */
+
+ list_node_t tvs_list_node;
+};
+
+typedef struct tem_callbacks {
+ void (*tsc_display)(struct tem_vt_state *, term_char_t *, int,
+ screen_pos_t, screen_pos_t);
+ void (*tsc_copy)(struct tem_vt_state *,
+ screen_pos_t, screen_pos_t, screen_pos_t, screen_pos_t,
+ screen_pos_t, screen_pos_t);
+ void (*tsc_cursor)(struct tem_vt_state *, short);
+ void (*tsc_bit2pix)(struct tem_vt_state *, term_char_t);
+ void (*tsc_cls)(struct tem_vt_state *, int, screen_pos_t, screen_pos_t);
+} tem_callbacks_t;
+
+typedef struct __tem_modechg_cb_arg *tem_modechg_cb_arg_t;
+typedef void (*tem_modechg_cb_t) (tem_modechg_cb_arg_t arg);
+typedef struct __tem_vt_state *tem_vt_state_t;
+
+/*
+ * common term soft state structure shared by all virtual terminal emulators
+ */
+typedef struct tem_state {
+ struct console *ts_hdl; /* Framework handle for dev */
+ screen_size_t ts_linebytes; /* Layered on bytes per scan line */
+
+ int ts_display_mode; /* What mode we are in */
+
+ struct tem_size ts_c_dimension; /* window dimensions in characters */
+ struct tem_size ts_p_dimension; /* screen dimensions in pixels */
+ struct tem_pix_pos ts_p_offset; /* pix offset to center the display */
+
+ int ts_pix_data_size; /* size of bitmap data areas */
+ int ts_pdepth; /* pixel depth */
+ struct font ts_font; /* font table */
+ bool update_font; /* flag the font change */
+
+ tem_callbacks_t *ts_callbacks; /* internal output functions */
+
+ int ts_initialized; /* initialization flag */
+
+ tem_modechg_cb_t ts_modechg_cb;
+ tem_modechg_cb_arg_t ts_modechg_arg;
+
+ color_map_fn_t ts_color_map;
+
+ tem_color_t ts_init_color; /* initial color and attributes */
+
+ struct tem_vt_state *ts_active;
+ list_t ts_list; /* chain of all tems */
+} tem_state_t;
+
+extern tem_state_t tems;
+/*
+ * tems_* fuctions mean that they just operate on the common soft state
+ * (tem_state_t), and tem_* functions mean that they operate on the
+ * per-tem structure (tem_vt_state). All "safe" interfaces are in tem_safe.c.
+ */
+int tems_cls(struct vis_consclear *);
+void tems_display(struct vis_consdisplay *);
+void tems_copy(struct vis_conscopy *);
+void tems_cursor(struct vis_conscursor *);
+
+int tem_initialized(tem_vt_state_t);
+
+tem_vt_state_t tem_init(void);
+
+int tem_info_init(struct console *);
+void tem_write(tem_vt_state_t, uint8_t *, ssize_t);
+void tem_get_size(uint16_t *, uint16_t *, uint16_t *, uint16_t *);
+void tem_save_state(void);
+void tem_register_modechg_cb(tem_modechg_cb_t, tem_modechg_cb_arg_t);
+void tem_activate(tem_vt_state_t, boolean_t);
+void tem_get_colors(tem_vt_state_t, text_color_t *, text_color_t *);
+void tem_image_display(struct tem_vt_state *, screen_pos_t, screen_pos_t,
+ screen_pos_t, screen_pos_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_TEM_H */
diff --git a/usr/src/boot/sys/sys/types.h b/usr/src/boot/sys/sys/types.h
index 81168bdff4..861cee3b39 100644
--- a/usr/src/boot/sys/sys/types.h
+++ b/usr/src/boot/sys/sys/types.h
@@ -294,6 +294,10 @@ typedef _Bool bool;
#define offsetof(type, field) __offsetof(type, field)
+#else
+/* for illumos compatibility */
+typedef enum boolean { B_FALSE, B_TRUE } boolean_t;
+
#endif /* !_KERNEL */
/*
diff --git a/usr/src/common/ficl/ficlplatform/pager.c b/usr/src/common/ficl/ficlplatform/pager.c
index f297945dbb..115353d181 100644
--- a/usr/src/common/ficl/ficlplatform/pager.c
+++ b/usr/src/common/ficl/ficlplatform/pager.c
@@ -67,7 +67,7 @@ pager_open(void)
nlines = 24; /* sensible default */
if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_row == 0) {
- if ((cp = getenv("LINES")) != NULL) {
+ if ((cp = getenv("screen-#rows")) != NULL) {
nlines = strtol(cp, &lp, 0);
}
} else
diff --git a/usr/src/common/ficl/loader.c b/usr/src/common/ficl/loader.c
index d581015c5c..a2172d11bb 100644
--- a/usr/src/common/ficl/loader.c
+++ b/usr/src/common/ficl/loader.c
@@ -43,6 +43,7 @@
#include <termios.h>
#else
#include <stand.h>
+#include <gfx_fb.h>
#include "bootstrap.h"
#endif
#ifdef _STANDALONE
@@ -69,6 +70,114 @@
* .# ( value -- )
*/
+#ifdef _STANDALONE
+void
+ficl_fb_putimage(ficlVm *pVM)
+{
+ char *namep, *name;
+ ficlUnsigned names;
+ ficlInteger ret = FICL_FALSE;
+ png_t png;
+
+ FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 1);
+
+ names = ficlStackPopUnsigned(ficlVmGetDataStack(pVM));
+ namep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM));
+
+ name = ficlMalloc(names+1);
+ if (!name)
+ ficlVmThrowError(pVM, "Error: out of memory");
+ strncpy(name, namep, names);
+ name[names] = '\0';
+
+ if (png_open(&png, name) != PNG_NO_ERROR) {
+ ret = FICL_FALSE;
+ ficlFree(name);
+ ficlStackPushInteger(ficlVmGetDataStack(pVM), ret);
+ return;
+ }
+
+ if (gfx_fb_putimage(&png) == 0)
+ ret = FICL_TRUE; /* success */
+ png_close(&png);
+ ficlFree(name);
+ ficlStackPushInteger(ficlVmGetDataStack(pVM), ret);
+}
+
+void
+ficl_fb_setpixel(ficlVm *pVM)
+{
+ ficlUnsigned x, y;
+
+ FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 0);
+
+ y = ficlStackPopUnsigned(ficlVmGetDataStack(pVM));
+ x = ficlStackPopUnsigned(ficlVmGetDataStack(pVM));
+ gfx_fb_setpixel(x, y);
+}
+
+void
+ficl_fb_line(ficlVm *pVM)
+{
+ ficlUnsigned x0, y0, x1, y1, wd;
+
+ FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 5, 0);
+
+ wd = ficlStackPopUnsigned(ficlVmGetDataStack(pVM));
+ y1 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM));
+ x1 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM));
+ y0 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM));
+ x0 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM));
+ gfx_fb_line(x0, y0, x1, y1, wd);
+}
+
+void
+ficl_fb_bezier(ficlVm *pVM)
+{
+ ficlUnsigned x0, y0, x1, y1, x2, y2, width;
+
+ FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 7, 0);
+
+ width = ficlStackPopUnsigned(ficlVmGetDataStack(pVM));
+ y2 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM));
+ x2 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM));
+ y1 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM));
+ x1 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM));
+ y0 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM));
+ x0 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM));
+ gfx_fb_bezier(x0, y0, x1, y1, x2, y2, width);
+}
+
+void
+ficl_fb_drawrect(ficlVm *pVM)
+{
+ ficlUnsigned x1, x2, y1, y2, fill;
+
+ FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 5, 0);
+
+ fill = ficlStackPopUnsigned(ficlVmGetDataStack(pVM));
+ y2 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM));
+ x2 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM));
+ y1 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM));
+ x1 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM));
+ gfx_fb_drawrect(x1, y1, x2, y2, fill);
+}
+
+void
+ficl_term_drawrect(ficlVm *pVM)
+{
+ ficlUnsigned x1, x2, y1, y2;
+
+ FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 4, 0);
+
+ y2 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM));
+ x2 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM));
+ y1 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM));
+ x1 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM));
+ gfx_term_drawrect(x1, y1, x2, y2);
+}
+#endif /* _STANDALONE */
+
void
ficlSetenv(ficlVm *pVM)
{
@@ -915,6 +1024,18 @@ ficlSystemCompilePlatform(ficlSystem *pSys)
ficlDictionarySetPrimitive(dp, "uuid-to-string", ficlUuidToString,
FICL_WORD_DEFAULT);
#ifdef _STANDALONE
+ ficlDictionarySetPrimitive(dp, "fb-setpixel", ficl_fb_setpixel,
+ FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "fb-line", ficl_fb_line,
+ FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "fb-bezier", ficl_fb_bezier,
+ FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "fb-drawrect", ficl_fb_drawrect,
+ FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "fb-putimage", ficl_fb_putimage,
+ FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "term-drawrect", ficl_term_drawrect,
+ FICL_WORD_DEFAULT);
/* Register words from linker set. */
SET_FOREACH(fnpp, Xficl_compile_set)
(*fnpp)(pSys);
diff --git a/usr/src/common/ficl/main.c b/usr/src/common/ficl/main.c
index 78ea2d3a00..b625c6d84c 100644
--- a/usr/src/common/ficl/main.c
+++ b/usr/src/common/ficl/main.c
@@ -102,10 +102,10 @@ main(int argc, char **argv)
clearenv();
asprintf(&buffer, "%d", cols);
- setenv("COLUMNS", buffer, 1);
+ setenv("screen-#cols", buffer, 1);
free(buffer);
asprintf(&buffer, "%d", rows);
- setenv("LINES", buffer, 1);
+ setenv("screen-#rows", buffer, 1);
free(buffer);
if (getenv("prompt") == NULL)
diff --git a/usr/src/common/ficl/tools.c b/usr/src/common/ficl/tools.c
index 39759b388a..2c1227ee7c 100644
--- a/usr/src/common/ficl/tools.c
+++ b/usr/src/common/ficl/tools.c
@@ -724,7 +724,7 @@ ficlPrimitiveWords(ficlVm *vm)
char *pPad;
int columns;
- cp = getenv("COLUMNS");
+ cp = getenv("screen-#cols");
/*
* using strtol for now. TODO: refactor number conversion from
* ficlPrimitiveToNumber() and use it instead.
diff --git a/usr/src/common/font/font.c b/usr/src/common/font/font.c
new file mode 100644
index 0000000000..f7a1abd914
--- /dev/null
+++ b/usr/src/common/font/font.c
@@ -0,0 +1,569 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright 2017 Toomas Soome <tsoome@me.com>
+ */
+
+/*
+ * Generic font related data and functions shared by early boot console
+ * in dboot, kernel startup and full kernel.
+ */
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/tem_impl.h>
+#include <sys/font.h>
+#include <sys/sysmacros.h>
+
+/*
+ * To simplify my life, I am "temporarily" collecting the commonly used
+ * color bits here. The bits shared between loader, dboot, early boot, tem.
+ * This data would need some sort of API, but I am in no condition to figure
+ * something out right now.
+ */
+
+/* ANSI color to sun color translation. */
+/* BEGIN CSTYLED */
+/* Bk Rd Gr Br Bl Mg Cy Wh */
+const uint8_t dim_xlate[] = { 1, 5, 3, 7, 2, 6, 4, 8 };
+const uint8_t brt_xlate[] = { 9, 13, 11, 15, 10, 14, 12, 0 };
+
+/* The pc color here is actually referring to standard 16 color VGA map. */
+typedef enum pc_colors {
+ pc_black = 0,
+ pc_blue = 1,
+ pc_green = 2,
+ pc_cyan = 3,
+ pc_red = 4,
+ pc_magenta = 5,
+ pc_brown = 6,
+ pc_white = 7,
+ pc_grey = 8,
+ pc_brt_blue = 9,
+ pc_brt_green = 10,
+ pc_brt_cyan = 11,
+ pc_brt_red = 12,
+ pc_brt_magenta = 13,
+ pc_yellow = 14,
+ pc_brt_white = 15
+} pc_colors_t;
+
+const uint8_t solaris_color_to_pc_color[16] = {
+ pc_brt_white, /* 0 - brt_white */
+ pc_black, /* 1 - black */
+ pc_blue, /* 2 - blue */
+ pc_green, /* 3 - green */
+ pc_cyan, /* 4 - cyan */
+ pc_red, /* 5 - red */
+ pc_magenta, /* 6 - magenta */
+ pc_brown, /* 7 - brown */
+ pc_white, /* 8 - white */
+ pc_grey, /* 9 - gery */
+ pc_brt_blue, /* 10 - brt_blue */
+ pc_brt_green, /* 11 - brt_green */
+ pc_brt_cyan, /* 12 - brt_cyan */
+ pc_brt_red, /* 13 - brt_red */
+ pc_brt_magenta, /* 14 - brt_magenta */
+ pc_yellow /* 15 - yellow */
+};
+
+/* 4-bit to 24-bit color translation. */
+const text_cmap_t cmap4_to_24 = {
+/* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+ Wh+ Bk Bl Gr Cy Rd Mg Br Wh Bk+ Bl+ Gr+ Cy+ Rd+ Mg+ Yw */
+ .red = {
+ 0xff,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x40,0x00,0x00,0x00,0xff,0xff,0xff
+},
+ .green = {
+ 0xff,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x80,0x40,0x00,0xff,0xff,0x00,0x00,0xff
+},
+ .blue = {
+ 0xff,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x40,0xff,0x00,0xff,0x00,0xff,0x00
+}
+};
+/* END CSTYLED */
+
+/*
+ * Fonts are statically linked with this module. At some point an
+ * RFE might be desireable to allow dynamic font loading. The
+ * original intention to facilitate dynamic fonts can be seen
+ * by examining the data structures and set_font(). As much of
+ * the original code is retained but modified to be suited for
+ * traversing a list of static fonts.
+ */
+
+/*
+ * Must be sorted by font size in descending order
+ */
+font_list_t fonts = STAILQ_HEAD_INITIALIZER(fonts);
+
+bitmap_data_t *
+set_font(short *rows, short *cols, short h, short w)
+{
+ bitmap_data_t *font = NULL;
+ struct fontlist *fl;
+ unsigned height = h;
+ unsigned width = w;
+
+ /*
+ * First check for manually loaded font.
+ */
+ STAILQ_FOREACH(fl, &fonts, font_next) {
+ if (fl->font_flags == FONT_MANUAL ||
+ fl->font_flags == FONT_BOOT) {
+ font = fl->font_data;
+ if (font->font == NULL && fl->font_load != NULL &&
+ fl->font_name != NULL) {
+ font = fl->font_load(fl->font_name);
+ }
+ if (font == NULL || font->font == NULL)
+ font = NULL;
+ break;
+ }
+ }
+
+ if (font != NULL) {
+ *rows = (height - BORDER_PIXELS) / font->height;
+ *cols = (width - BORDER_PIXELS) / font->width;
+ return (font);
+ }
+
+ /*
+ * Find best font for these dimensions, or use default
+ *
+ * A 1 pixel border is the absolute minimum we could have
+ * as a border around the text window (BORDER_PIXELS = 2),
+ * however a slightly larger border not only looks better
+ * but for the fonts currently statically built into the
+ * emulator causes much better font selection for the
+ * normal range of screen resolutions.
+ */
+ STAILQ_FOREACH(fl, &fonts, font_next) {
+ font = fl->font_data;
+ if ((((*rows * font->height) + BORDER_PIXELS) <= height) &&
+ (((*cols * font->width) + BORDER_PIXELS) <= width)) {
+ if (font->font == NULL) {
+ if (fl->font_load != NULL &&
+ fl->font_name != NULL) {
+ font = fl->font_load(fl->font_name);
+ }
+ if (font == NULL)
+ continue;
+ }
+ *rows = (height - BORDER_PIXELS) / font->height;
+ *cols = (width - BORDER_PIXELS) / font->width;
+ break;
+ }
+ font = NULL;
+ }
+
+ if (font == NULL) {
+ /*
+ * We have fonts sorted smallest last, try it before
+ * falling back to builtin.
+ */
+ fl = STAILQ_LAST(&fonts, fontlist, font_next);
+ if (fl != NULL && fl->font_load != NULL &&
+ fl->font_name != NULL) {
+ font = fl->font_load(fl->font_name);
+ }
+ if (font == NULL)
+ font = &DEFAULT_FONT_DATA;
+
+ *rows = (height - BORDER_PIXELS) / font->height;
+ *cols = (width - BORDER_PIXELS) / font->width;
+ }
+
+ return (font);
+}
+
+/* Binary search for the glyph. Return 0 if not found. */
+static uint16_t
+font_bisearch(const struct font_map *map, uint32_t len, uint32_t src)
+{
+ unsigned min, mid, max;
+
+ min = 0;
+ max = len - 1;
+
+ /* Empty font map. */
+ if (len == 0)
+ return (0);
+ /* Character below minimal entry. */
+ if (src < map[0].font_src)
+ return (0);
+ /* Optimization: ASCII characters occur very often. */
+ if (src <= map[0].font_src + map[0].font_len)
+ return (src - map[0].font_src + map[0].font_dst);
+ /* Character above maximum entry. */
+ if (src > map[max].font_src + map[max].font_len)
+ return (0);
+
+ /* Binary search. */
+ while (max >= min) {
+ mid = (min + max) / 2;
+ if (src < map[mid].font_src)
+ max = mid - 1;
+ else if (src > map[mid].font_src + map[mid].font_len)
+ min = mid + 1;
+ else
+ return (src - map[mid].font_src + map[mid].font_dst);
+ }
+
+ return (0);
+}
+
+/*
+ * Return glyph bitmap. If glyph is not found, we will return bitmap
+ * for the first (offset 0) glyph.
+ */
+const uint8_t *
+font_lookup(const struct font *vf, uint32_t c)
+{
+ uint32_t src;
+ uint16_t dst;
+ size_t stride;
+
+ src = TEM_CHAR(c);
+
+ /* Substitute bold with normal if not found. */
+ if (TEM_CHAR_ATTR(c) & TEM_ATTR_BOLD) {
+ dst = font_bisearch(vf->vf_map[VFNT_MAP_BOLD],
+ vf->vf_map_count[VFNT_MAP_BOLD], src);
+ if (dst != 0)
+ goto found;
+ }
+ dst = font_bisearch(vf->vf_map[VFNT_MAP_NORMAL],
+ vf->vf_map_count[VFNT_MAP_NORMAL], src);
+
+found:
+ stride = howmany(vf->vf_width, 8) * vf->vf_height;
+ return (&vf->vf_bytes[dst * stride]);
+}
+
+/*
+ * bit_to_pix4 is for 4-bit frame buffers. It will write one output byte
+ * for each 2 bits of input bitmap. It inverts the input bits before
+ * doing the output translation, for reverse video.
+ *
+ * Assuming foreground is 0001 and background is 0000...
+ * An input data byte of 0x53 will output the bit pattern
+ * 00000001 00000001 00000000 00010001.
+ */
+
+void
+font_bit_to_pix4(
+ struct font *f,
+ uint8_t *dest,
+ uint32_t c,
+ uint8_t fg_color,
+ uint8_t bg_color)
+{
+ uint32_t row;
+ int byte;
+ int i;
+ const uint8_t *cp, *ul;
+ uint8_t data;
+ uint8_t nibblett;
+ int bytes_wide;
+
+ if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE)
+ ul = font_lookup(f, 0x0332); /* combining low line */
+ else
+ ul = NULL;
+
+ cp = font_lookup(f, c);
+ bytes_wide = (f->vf_width + 7) / 8;
+
+ for (row = 0; row < f->vf_height; row++) {
+ for (byte = 0; byte < bytes_wide; byte++) {
+ if (ul == NULL)
+ data = *cp++;
+ else
+ data = *cp++ | *ul++;
+ for (i = 0; i < 4; i++) {
+ nibblett = (data >> ((3-i) * 2)) & 0x3;
+ switch (nibblett) {
+ case 0x0:
+ *dest++ = bg_color << 4 | bg_color;
+ break;
+ case 0x1:
+ *dest++ = bg_color << 4 | fg_color;
+ break;
+ case 0x2:
+ *dest++ = fg_color << 4 | bg_color;
+ break;
+ case 0x3:
+ *dest++ = fg_color << 4 | fg_color;
+ break;
+ }
+ }
+ }
+ }
+}
+
+/*
+ * bit_to_pix8 is for 8-bit frame buffers. It will write one output byte
+ * for each bit of input bitmap. It inverts the input bits before
+ * doing the output translation, for reverse video.
+ *
+ * Assuming foreground is 00000001 and background is 00000000...
+ * An input data byte of 0x53 will output the bit pattern
+ * 0000000 000000001 00000000 00000001 00000000 00000000 00000001 00000001.
+ */
+
+void
+font_bit_to_pix8(
+ struct font *f,
+ uint8_t *dest,
+ uint32_t c,
+ uint8_t fg_color,
+ uint8_t bg_color)
+{
+ uint32_t row;
+ int byte;
+ int i;
+ const uint8_t *cp, *ul;
+ uint8_t data;
+ int bytes_wide;
+ uint8_t mask;
+ int bitsleft, nbits;
+
+ if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE)
+ ul = font_lookup(f, 0x0332); /* combining low line */
+ else
+ ul = NULL;
+
+ cp = font_lookup(f, c);
+ bytes_wide = (f->vf_width + 7) / 8;
+
+ for (row = 0; row < f->vf_height; row++) {
+ bitsleft = f->vf_width;
+ for (byte = 0; byte < bytes_wide; byte++) {
+ if (ul == NULL)
+ data = *cp++;
+ else
+ data = *cp++ | *ul++;
+ mask = 0x80;
+ nbits = MIN(8, bitsleft);
+ bitsleft -= nbits;
+ for (i = 0; i < nbits; i++) {
+ *dest++ = (data & mask ? fg_color: bg_color);
+ mask = mask >> 1;
+ }
+ }
+ }
+}
+
+/*
+ * bit_to_pix16 is for 16-bit frame buffers. It will write two output bytes
+ * for each bit of input bitmap. It inverts the input bits before
+ * doing the output translation, for reverse video.
+ *
+ * Assuming foreground is 11111111 11111111
+ * and background is 00000000 00000000
+ * An input data byte of 0x53 will output the bit pattern
+ *
+ * 00000000 00000000
+ * 11111111 11111111
+ * 00000000 00000000
+ * 11111111 11111111
+ * 00000000 00000000
+ * 00000000 00000000
+ * 11111111 11111111
+ * 11111111 11111111
+ *
+ */
+
+void
+font_bit_to_pix16(
+ struct font *f,
+ uint16_t *dest,
+ uint32_t c,
+ uint16_t fg_color16,
+ uint16_t bg_color16)
+{
+ uint32_t row;
+ int byte;
+ int i;
+ const uint8_t *cp, *ul;
+ uint16_t data, d;
+ int bytes_wide;
+ int bitsleft, nbits;
+
+ if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE)
+ ul = font_lookup(f, 0x0332); /* combining low line */
+ else
+ ul = NULL;
+
+ cp = font_lookup(f, c);
+ bytes_wide = (f->vf_width + 7) / 8;
+
+ for (row = 0; row < f->vf_height; row++) {
+ bitsleft = f->vf_width;
+ for (byte = 0; byte < bytes_wide; byte++) {
+ if (ul == NULL)
+ data = *cp++;
+ else
+ data = *cp++ | *ul++;
+ nbits = MIN(8, bitsleft);
+ bitsleft -= nbits;
+ for (i = 0; i < nbits; i++) {
+ d = ((data << i) & 0x80 ?
+ fg_color16 : bg_color16);
+ *dest++ = d;
+ }
+ }
+ }
+}
+
+/*
+ * bit_to_pix24 is for 24-bit frame buffers. It will write three output bytes
+ * for each bit of input bitmap. It inverts the input bits before
+ * doing the output translation, for reverse video.
+ *
+ * Assuming foreground is 11111111 11111111 11111111
+ * and background is 00000000 00000000 00000000
+ * An input data byte of 0x53 will output the bit pattern
+ *
+ * 00000000 00000000 00000000
+ * 11111111 11111111 11111111
+ * 00000000 00000000 00000000
+ * 11111111 11111111 11111111
+ * 00000000 00000000 00000000
+ * 00000000 00000000 00000000
+ * 11111111 11111111 11111111
+ * 11111111 11111111 11111111
+ *
+ */
+
+void
+font_bit_to_pix24(
+ struct font *f,
+ uint8_t *dest,
+ uint32_t c,
+ uint32_t fg_color32,
+ uint32_t bg_color32)
+{
+ uint32_t row;
+ int byte;
+ int i;
+ const uint8_t *cp, *ul;
+ uint32_t data, d;
+ int bytes_wide;
+ int bitsleft, nbits;
+
+ if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE)
+ ul = font_lookup(f, 0x0332); /* combining low line */
+ else
+ ul = NULL;
+
+ cp = font_lookup(f, c);
+ bytes_wide = (f->vf_width + 7) / 8;
+
+ for (row = 0; row < f->vf_height; row++) {
+ bitsleft = f->vf_width;
+ for (byte = 0; byte < bytes_wide; byte++) {
+ if (ul == NULL)
+ data = *cp++;
+ else
+ data = *cp++ | *ul++;
+
+ nbits = MIN(8, bitsleft);
+ bitsleft -= nbits;
+ for (i = 0; i < nbits; i++) {
+ d = ((data << i) & 0x80 ?
+ fg_color32 : bg_color32);
+ *dest++ = d & 0xff;
+ *dest++ = (d >> 8) & 0xff;
+ *dest++ = (d >> 16) & 0xff;
+ }
+ }
+ }
+}
+
+/*
+ * bit_to_pix32 is for 32-bit frame buffers. It will write four output bytes
+ * for each bit of input bitmap. It inverts the input bits before
+ * doing the output translation, for reverse video. Note that each
+ * 24-bit RGB value is finally stored in a 32-bit unsigned int, with the
+ * high-order byte set to zero.
+ *
+ * Assuming foreground is 00000000 11111111 11111111 11111111
+ * and background is 00000000 00000000 00000000 00000000
+ * An input data byte of 0x53 will output the bit pattern
+ *
+ * 00000000 00000000 00000000 00000000
+ * 00000000 11111111 11111111 11111111
+ * 00000000 00000000 00000000 00000000
+ * 00000000 11111111 11111111 11111111
+ * 00000000 00000000 00000000 00000000
+ * 00000000 00000000 00000000 00000000
+ * 00000000 11111111 11111111 11111111
+ * 00000000 11111111 11111111 11111111
+ *
+ */
+
+void
+font_bit_to_pix32(
+ struct font *f,
+ uint32_t *dest,
+ uint32_t c,
+ uint32_t fg_color32,
+ uint32_t bg_color32)
+{
+ uint32_t row;
+ int byte;
+ int i;
+ const uint8_t *cp, *ul;
+ uint32_t data;
+ int bytes_wide;
+ int bitsleft, nbits;
+
+ if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE)
+ ul = font_lookup(f, 0x0332); /* combining low line */
+ else
+ ul = NULL;
+
+ cp = font_lookup(f, c);
+ bytes_wide = (f->vf_width + 7) / 8;
+
+ for (row = 0; row < f->vf_height; row++) {
+ bitsleft = f->vf_width;
+ for (byte = 0; byte < bytes_wide; byte++) {
+ if (ul == NULL)
+ data = *cp++;
+ else
+ data = *cp++ | *ul++;
+ nbits = MIN(8, bitsleft);
+ bitsleft -= nbits;
+ for (i = 0; i < nbits; i++) {
+ *dest++ = ((data << i) & 0x80 ?
+ fg_color32 : bg_color32);
+ }
+ }
+ }
+}
diff --git a/usr/src/common/pnglite/THIRDPARTYLICENSE b/usr/src/common/pnglite/THIRDPARTYLICENSE
new file mode 100644
index 0000000000..7f9379bbf9
--- /dev/null
+++ b/usr/src/common/pnglite/THIRDPARTYLICENSE
@@ -0,0 +1,26 @@
+/*
+ * pnglite.h - Interface for pnglite library
+ * Copyright (c) 2007 Daniel Karling
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source
+ * distribution.
+ *
+ * Daniel Karling
+ * daniel.karling@gmail.com
+ */
diff --git a/usr/src/common/pnglite/THIRDPARTYLICENSE.descrip b/usr/src/common/pnglite/THIRDPARTYLICENSE.descrip
new file mode 100644
index 0000000000..64d37cdaba
--- /dev/null
+++ b/usr/src/common/pnglite/THIRDPARTYLICENSE.descrip
@@ -0,0 +1 @@
+pnglite
diff --git a/usr/src/common/pnglite/pnglite.c b/usr/src/common/pnglite/pnglite.c
new file mode 100644
index 0000000000..59b9df1db6
--- /dev/null
+++ b/usr/src/common/pnglite/pnglite.c
@@ -0,0 +1,620 @@
+/*
+ * pnglite.c - pnglite library
+ * For conditions of distribution and use, see copyright notice in pnglite.h
+ */
+
+#ifdef _STANDALONE
+#include <sys/cdefs.h>
+#include <stand.h>
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#endif
+#include <zlib.h>
+#include "pnglite.h"
+
+#ifndef abs
+#define abs(x) ((x) < 0? -(x):(x))
+#endif
+
+#define PNG_32b(b, s) ((uint32_t)(b) << (s))
+#define PNG_U32(b1, b2, b3, b4) \
+ (PNG_32b(b1, 24) | PNG_32b(b2, 16) | PNG_32b(b3, 8) | PNG_32b(b4, 0))
+
+#define png_IDAT PNG_U32(73, 68, 65, 84)
+#define png_IEND PNG_U32(73, 69, 78, 68)
+
+static ssize_t
+file_read(png_t *png, void *out, size_t size, size_t numel)
+{
+ ssize_t result;
+ off_t offset = (off_t)(size * numel);
+
+ if (offset < 0)
+ return (PNG_FILE_ERROR);
+
+ if (!out) {
+ result = lseek(png->fd, offset, SEEK_CUR);
+ } else {
+ result = read(png->fd, out, size * numel);
+ }
+
+ return (result);
+}
+
+static int
+file_read_ul(png_t *png, unsigned *out)
+{
+ uint8_t buf[4];
+
+ if (file_read(png, buf, 1, 4) != 4)
+ return (PNG_FILE_ERROR);
+
+ *out = (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3];
+
+ return (PNG_NO_ERROR);
+}
+
+static unsigned
+get_ul(uint8_t *buf)
+{
+ unsigned result;
+ uint8_t foo[4];
+
+ memcpy(foo, buf, 4);
+
+ result = (foo[0]<<24) | (foo[1]<<16) | (foo[2]<<8) | foo[3];
+
+ return (result);
+}
+
+static int
+png_get_bpp(png_t *png)
+{
+ int bpp;
+
+ switch (png->color_type) {
+ case PNG_GREYSCALE:
+ bpp = 1; break;
+ case PNG_TRUECOLOR:
+ bpp = 3; break;
+ case PNG_INDEXED:
+ bpp = 1; break;
+ case PNG_GREYSCALE_ALPHA:
+ bpp = 2; break;
+ case PNG_TRUECOLOR_ALPHA:
+ bpp = 4; break;
+ default:
+ return (PNG_FILE_ERROR);
+ }
+
+ bpp *= png->depth / 8;
+
+ return (bpp);
+}
+
+static int
+png_read_ihdr(png_t *png)
+{
+ unsigned length;
+ unsigned orig_crc;
+ unsigned calc_crc;
+ uint8_t ihdr[13+4]; /* length should be 13, make room for type (IHDR) */
+
+ file_read_ul(png, &length);
+
+ if (length != 13)
+ return (PNG_CRC_ERROR);
+
+ if (file_read(png, ihdr, 1, 13+4) != 13+4)
+ return (PNG_EOF_ERROR);
+
+ file_read_ul(png, &orig_crc);
+
+ calc_crc = crc32(0L, Z_NULL, 0);
+ calc_crc = crc32(calc_crc, ihdr, 13+4);
+
+ if (orig_crc != calc_crc) {
+ return (PNG_CRC_ERROR);
+ }
+
+ png->width = get_ul(ihdr+4);
+ png->height = get_ul(ihdr+8);
+ png->depth = ihdr[12];
+ png->color_type = ihdr[13];
+ png->compression_method = ihdr[14];
+ png->filter_method = ihdr[15];
+ png->interlace_method = ihdr[16];
+
+ if (png->color_type == PNG_INDEXED)
+ return (PNG_NOT_SUPPORTED);
+
+ if (png->depth != 8 && png->depth != 16)
+ return (PNG_NOT_SUPPORTED);
+
+ if (png->interlace_method)
+ return (PNG_NOT_SUPPORTED);
+
+ return (PNG_NO_ERROR);
+}
+
+void
+png_print_info(png_t *png)
+{
+ printf("PNG INFO:\n");
+ printf("\twidth:\t\t%d\n", png->width);
+ printf("\theight:\t\t%d\n", png->height);
+ printf("\tdepth:\t\t%d\n", png->depth);
+ printf("\tcolor:\t\t");
+
+ switch (png->color_type) {
+ case PNG_GREYSCALE:
+ printf("greyscale\n"); break;
+ case PNG_TRUECOLOR:
+ printf("truecolor\n"); break;
+ case PNG_INDEXED:
+ printf("palette\n"); break;
+ case PNG_GREYSCALE_ALPHA:
+ printf("greyscale with alpha\n"); break;
+ case PNG_TRUECOLOR_ALPHA:
+ printf("truecolor with alpha\n"); break;
+ default:
+ printf("unknown, this is not good\n"); break;
+ }
+
+ printf("\tcompression:\t%s\n",
+ png->compression_method?
+ "unknown, this is not good":"inflate/deflate");
+ printf("\tfilter:\t\t%s\n",
+ png->filter_method? "unknown, this is not good":"adaptive");
+ printf("\tinterlace:\t%s\n",
+ png->interlace_method? "interlace":"no interlace");
+}
+
+int
+png_open(png_t *png, const char *filename)
+{
+ char header[8];
+ int result;
+
+ png->image = NULL;
+ png->fd = open(filename, O_RDONLY);
+ if (png->fd == -1)
+ return (PNG_FILE_ERROR);
+
+ if (file_read(png, header, 1, 8) != 8) {
+ result = PNG_EOF_ERROR;
+ goto done;
+ }
+
+ if (memcmp(header, "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", 8) != 0) {
+ result = PNG_HEADER_ERROR;
+ goto done;
+ }
+
+ result = png_read_ihdr(png);
+ if (result == PNG_NO_ERROR) {
+ result = png_get_bpp(png);
+ if (result > 0) {
+ png->bpp = (uint8_t)result;
+ result = PNG_NO_ERROR;
+ }
+ }
+
+done:
+ if (result == PNG_NO_ERROR) {
+ uint64_t size = png->width * png->height * png->bpp;
+
+ if (size < UINT_MAX)
+ png->image = malloc(size);
+ if (png->image == NULL)
+ result = PNG_MEMORY_ERROR;
+ }
+
+ if (result == PNG_NO_ERROR)
+ result = png_get_data(png, png->image);
+
+ if (result != PNG_NO_ERROR) {
+ free(png->image);
+ close(png->fd);
+ png->fd = -1;
+ return (result);
+ }
+
+ return (result);
+}
+
+int
+png_close(png_t *png)
+{
+ close(png->fd);
+ png->fd = -1;
+ free(png->image);
+ png->image = NULL;
+
+ return (PNG_NO_ERROR);
+}
+
+static int
+png_init_inflate(png_t *png)
+{
+ z_stream *stream;
+ png->zs = calloc(1, sizeof (z_stream));
+
+ stream = png->zs;
+
+ if (!stream)
+ return (PNG_MEMORY_ERROR);
+
+ if (inflateInit(stream) != Z_OK) {
+ free(png->zs);
+ png->zs = NULL;
+ return (PNG_ZLIB_ERROR);
+ }
+
+ stream->next_out = png->png_data;
+ stream->avail_out = png->png_datalen;
+
+ return (PNG_NO_ERROR);
+}
+
+static int
+png_end_inflate(png_t *png)
+{
+ z_stream *stream = png->zs;
+ int rc = PNG_NO_ERROR;
+
+ if (!stream)
+ return (PNG_MEMORY_ERROR);
+
+ if (inflateEnd(stream) != Z_OK) {
+ printf("ZLIB says: %s\n", stream->msg);
+ rc = PNG_ZLIB_ERROR;
+ }
+
+ free(png->zs);
+ png->zs = NULL;
+
+ return (rc);
+}
+
+static int
+png_inflate(png_t *png, uint8_t *data, int len)
+{
+ int result;
+ z_stream *stream = png->zs;
+
+ if (!stream)
+ return (PNG_MEMORY_ERROR);
+
+ stream->next_in = data;
+ stream->avail_in = len;
+
+ result = inflate(stream, Z_SYNC_FLUSH);
+
+ if (result != Z_STREAM_END && result != Z_OK) {
+ printf("%s\n", stream->msg);
+ return (PNG_ZLIB_ERROR);
+ }
+
+ if (stream->avail_in != 0)
+ return (PNG_ZLIB_ERROR);
+
+ return (PNG_NO_ERROR);
+}
+
+static int
+png_read_idat(png_t *png, unsigned length)
+{
+ unsigned orig_crc;
+ unsigned calc_crc;
+ ssize_t len = length;
+
+ if (!png->readbuf || png->readbuflen < length) {
+ png->readbuf = realloc(png->readbuf, length);
+ png->readbuflen = length;
+ }
+
+ if (!png->readbuf)
+ return (PNG_MEMORY_ERROR);
+
+ if (file_read(png, png->readbuf, 1, length) != len)
+ return (PNG_FILE_ERROR);
+
+ calc_crc = crc32(0L, Z_NULL, 0);
+ calc_crc = crc32(calc_crc, (uint8_t *)"IDAT", 4);
+ calc_crc = crc32(calc_crc, (uint8_t *)png->readbuf, length);
+
+ file_read_ul(png, &orig_crc);
+
+ if (orig_crc != calc_crc)
+ return (PNG_CRC_ERROR);
+
+ return (png_inflate(png, png->readbuf, length));
+}
+
+static int
+png_process_chunk(png_t *png)
+{
+ int result = PNG_NO_ERROR;
+ unsigned type;
+ unsigned length;
+
+ file_read_ul(png, &length);
+
+ if (file_read_ul(png, &type))
+ return (PNG_FILE_ERROR);
+
+ /*
+ * if we found an idat, all other idats should be followed with no
+ * other chunks in between
+ */
+ if (type == png_IDAT) {
+ if (!png->png_data) { /* first IDAT */
+ png->png_datalen = png->width * png->height *
+ png->bpp + png->height;
+ png->png_data = malloc(png->png_datalen);
+ }
+
+ if (!png->png_data)
+ return (PNG_MEMORY_ERROR);
+
+ if (!png->zs) {
+ result = png_init_inflate(png);
+ if (result != PNG_NO_ERROR)
+ return (result);
+ }
+
+ return (png_read_idat(png, length));
+ } else if (type == png_IEND)
+ return (PNG_DONE);
+ else
+ file_read(png, 0, 1, length + 4); /* unknown chunk */
+
+ return (result);
+}
+
+static void
+png_filter_sub(unsigned stride, uint8_t *in, uint8_t *out, unsigned len)
+{
+ unsigned i;
+ uint8_t a = 0;
+
+ for (i = 0; i < len; i++) {
+ if (i >= stride)
+ a = out[i - stride];
+
+ out[i] = in[i] + a;
+ }
+}
+
+static void
+png_filter_up(unsigned stride __unused, uint8_t *in, uint8_t *out,
+ uint8_t *prev_line, unsigned len)
+{
+ unsigned i;
+
+ if (prev_line) {
+ for (i = 0; i < len; i++)
+ out[i] = in[i] + prev_line[i];
+ } else
+ memcpy(out, in, len);
+}
+
+static void
+png_filter_average(unsigned stride, uint8_t *in, uint8_t *out,
+ uint8_t *prev_line, unsigned len)
+{
+ unsigned int i;
+ uint8_t a = 0;
+ uint8_t b = 0;
+ unsigned int sum = 0;
+
+ for (i = 0; i < len; i++) {
+ if (prev_line)
+ b = prev_line[i];
+
+ if (i >= stride)
+ a = out[i - stride];
+
+ sum = a;
+ sum += b;
+
+ out[i] = in[i] + sum/2;
+ }
+}
+
+static uint8_t
+png_paeth(uint8_t a, uint8_t b, uint8_t c)
+{
+ int p = (int)a + b - c;
+ int pa = abs(p - a);
+ int pb = abs(p - b);
+ int pc = abs(p - c);
+
+ int pr;
+
+ if (pa <= pb && pa <= pc)
+ pr = a;
+ else if (pb <= pc)
+ pr = b;
+ else
+ pr = c;
+
+ return (pr);
+}
+
+static void
+png_filter_paeth(unsigned stride, uint8_t *in, uint8_t *out, uint8_t *prev_line,
+ unsigned len)
+{
+ unsigned i;
+ uint8_t a;
+ uint8_t b;
+ uint8_t c;
+
+ for (i = 0; i < len; i++) {
+ if (prev_line && i >= stride) {
+ a = out[i - stride];
+ b = prev_line[i];
+ c = prev_line[i - stride];
+ } else {
+ if (prev_line)
+ b = prev_line[i];
+ else
+ b = 0;
+
+ if (i >= stride)
+ a = out[i - stride];
+ else
+ a = 0;
+
+ c = 0;
+ }
+
+ out[i] = in[i] + png_paeth(a, b, c);
+ }
+}
+
+static int
+png_unfilter(png_t *png, uint8_t *data)
+{
+ unsigned i;
+ unsigned pos = 0;
+ unsigned outpos = 0;
+ uint8_t *filtered = png->png_data;
+ unsigned stride = png->bpp;
+
+ while (pos < png->png_datalen) {
+ uint8_t filter = filtered[pos];
+
+ pos++;
+
+ if (png->depth == 16) {
+ for (i = 0; i < png->width * stride; i += 2) {
+ *(short *)(filtered+pos+i) =
+ (filtered[pos+i] << 8) | filtered[pos+i+1];
+ }
+ }
+
+ switch (filter) {
+ case 0: /* none */
+ memcpy(data+outpos, filtered+pos, png->width * stride);
+ break;
+ case 1: /* sub */
+ png_filter_sub(stride, filtered+pos, data+outpos,
+ png->width * stride);
+ break;
+ case 2: /* up */
+ if (outpos) {
+ png_filter_up(stride, filtered+pos, data+outpos,
+ data + outpos - (png->width*stride),
+ png->width*stride);
+ } else {
+ png_filter_up(stride, filtered+pos, data+outpos,
+ 0, png->width*stride);
+ }
+ break;
+ case 3: /* average */
+ if (outpos) {
+ png_filter_average(stride, filtered+pos,
+ data+outpos,
+ data + outpos - (png->width*stride),
+ png->width*stride);
+ } else {
+ png_filter_average(stride, filtered+pos,
+ data+outpos, 0, png->width*stride);
+ }
+ break;
+ case 4: /* paeth */
+ if (outpos) {
+ png_filter_paeth(stride, filtered+pos,
+ data+outpos,
+ data + outpos - (png->width*stride),
+ png->width*stride);
+ } else {
+ png_filter_paeth(stride, filtered+pos,
+ data+outpos, 0, png->width*stride);
+ }
+ break;
+ default:
+ return (PNG_UNKNOWN_FILTER);
+ }
+
+ outpos += png->width * stride;
+ pos += png->width * stride;
+ }
+
+ return (PNG_NO_ERROR);
+}
+
+int
+png_get_data(png_t *png, uint8_t *data)
+{
+ int result = PNG_NO_ERROR;
+
+ png->zs = NULL;
+ png->png_datalen = 0;
+ png->png_data = NULL;
+ png->readbuf = NULL;
+ png->readbuflen = 0;
+
+ while (result == PNG_NO_ERROR)
+ result = png_process_chunk(png);
+
+ if (png->readbuf) {
+ free(png->readbuf);
+ png->readbuflen = 0;
+ }
+ if (png->zs)
+ png_end_inflate(png);
+
+ if (result != PNG_DONE) {
+ free(png->png_data);
+ return (result);
+ }
+
+ result = png_unfilter(png, data);
+
+ free(png->png_data);
+
+ return (result);
+}
+
+char *
+png_error_string(int error)
+{
+ switch (error) {
+ case PNG_NO_ERROR:
+ return ("No error");
+ case PNG_FILE_ERROR:
+ return ("Unknown file error.");
+ case PNG_HEADER_ERROR:
+ return ("No PNG header found. Are you sure this is a PNG?");
+ case PNG_IO_ERROR:
+ return ("Failure while reading file.");
+ case PNG_EOF_ERROR:
+ return ("Reached end of file.");
+ case PNG_CRC_ERROR:
+ return ("CRC or chunk length error.");
+ case PNG_MEMORY_ERROR:
+ return ("Could not allocate memory.");
+ case PNG_ZLIB_ERROR:
+ return ("zlib reported an error.");
+ case PNG_UNKNOWN_FILTER:
+ return ("Unknown filter method used in scanline.");
+ case PNG_DONE:
+ return ("PNG done");
+ case PNG_NOT_SUPPORTED:
+ return ("The PNG is unsupported by pnglite, too bad for you!");
+ case PNG_WRONG_ARGUMENTS:
+ return ("Wrong combination of arguments passed to png_open. "
+ "You must use either a read_function or supply a file "
+ "pointer to use.");
+ default:
+ return ("Unknown error.");
+ };
+}
diff --git a/usr/src/common/pnglite/pnglite.h b/usr/src/common/pnglite/pnglite.h
new file mode 100644
index 0000000000..3c3a3320c2
--- /dev/null
+++ b/usr/src/common/pnglite/pnglite.h
@@ -0,0 +1,169 @@
+/*
+ * pnglite.h - Interface for pnglite library
+ * Copyright (c) 2007 Daniel Karling
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source
+ * distribution.
+ *
+ * Daniel Karling
+ * daniel.karling@gmail.com
+ */
+
+
+#ifndef _PNGLITE_H_
+#define _PNGLITE_H_
+
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Enumerations for pnglite.
+ * Negative numbers are error codes and 0 and up are okay responses.
+ */
+
+enum {
+ PNG_DONE = 1,
+ PNG_NO_ERROR = 0,
+ PNG_FILE_ERROR = -1,
+ PNG_HEADER_ERROR = -2,
+ PNG_IO_ERROR = -3,
+ PNG_EOF_ERROR = -4,
+ PNG_CRC_ERROR = -5,
+ PNG_MEMORY_ERROR = -6,
+ PNG_ZLIB_ERROR = -7,
+ PNG_UNKNOWN_FILTER = -8,
+ PNG_NOT_SUPPORTED = -9,
+ PNG_WRONG_ARGUMENTS = -10
+};
+
+/*
+ * The five different kinds of color storage in PNG files.
+ */
+
+enum {
+ PNG_GREYSCALE = 0,
+ PNG_TRUECOLOR = 2,
+ PNG_INDEXED = 3,
+ PNG_GREYSCALE_ALPHA = 4,
+ PNG_TRUECOLOR_ALPHA = 6
+};
+
+typedef struct {
+ void *zs; /* pointer to z_stream */
+ int fd;
+ unsigned char *image;
+
+ unsigned char *png_data;
+ unsigned png_datalen;
+
+ unsigned width;
+ unsigned height;
+ unsigned char depth;
+ unsigned char color_type;
+ unsigned char compression_method;
+ unsigned char filter_method;
+ unsigned char interlace_method;
+ unsigned char bpp;
+
+ unsigned char *readbuf;
+ unsigned readbuflen;
+} png_t;
+
+
+/*
+ * Function: png_open
+ *
+ * This function is used to open a png file with the internal file
+ * IO system.
+ *
+ * Parameters:
+ * png - Empty png_t struct.
+ * filename - Filename of the file to be opened.
+ *
+ * Returns:
+ * PNG_NO_ERROR on success, otherwise an error code.
+ */
+
+int png_open(png_t *png, const char *filename);
+
+/*
+ * Function: png_print_info
+ *
+ * This function prints some info about the opened png file to stdout.
+ *
+ * Parameters:
+ * png - png struct to get info from.
+ */
+
+void png_print_info(png_t *png);
+
+/*
+ * Function: png_error_string
+ *
+ * This function translates an error code to a human readable string.
+ *
+ * Parameters:
+ * error - Error code.
+ *
+ * Returns:
+ * Pointer to string.
+ */
+
+char *png_error_string(int error);
+
+/*
+ * Function: png_get_data
+ *
+ * This function decodes the opened png file and stores the result in data.
+ * data should be big enough to hold the decoded png.
+ * Required size will be:
+ *
+ * > width*height*(bytes per pixel)
+ *
+ * Parameters:
+ * data - Where to store result.
+ *
+ * Returns:
+ * PNG_NO_ERROR on success, otherwise an error code.
+ */
+
+int png_get_data(png_t *png, uint8_t *data);
+
+/*
+ * Function: png_close
+ *
+ * Closes an open png file pointer.
+ *
+ * Parameters:
+ * png - png to close.
+ *
+ * Returns:
+ * PNG_NO_ERROR
+ */
+
+int png_close(png_t *png);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PNGLITE_H_ */
diff --git a/usr/src/uts/common/io/vgasubr.c b/usr/src/common/vga/vgasubr.c
index 5fc151232a..ccd5e56ddc 100644
--- a/usr/src/uts/common/io/vgasubr.c
+++ b/usr/src/common/vga/vgasubr.c
@@ -22,14 +22,14 @@
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2018 Toomas Soome <tsoome@me.com>
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Support routines for VGA drivers
*/
+#if defined(_KERNEL)
#include <sys/debug.h>
#include <sys/types.h>
#include <sys/param.h>
@@ -39,8 +39,6 @@
#include <sys/systm.h>
#include <sys/conf.h>
-#include <sys/vgareg.h>
-#include <sys/vgasubr.h>
#include <sys/cmn_err.h>
#include <sys/kmem.h>
@@ -51,6 +49,21 @@
#include <sys/modctl.h>
+#define PUTB(reg, off, v) ddi_put8(reg->handle, reg->addr + (off), v)
+#define GETB(reg, off) ddi_get8(reg->handle, reg->addr + (off))
+
+#elif defined(_STANDALONE)
+
+#include <stand.h>
+#include <machine/cpufunc.h>
+
+#define PUTB(reg, off, v) outb(reg + (off), v)
+#define GETB(reg, off) inb(reg + (off))
+#endif
+
+#include <sys/vgareg.h>
+#include <sys/vgasubr.h>
+
#define GET_HORIZ_END(c) vga_get_crtc(c, VGA_CRTC_H_D_END)
#define GET_VERT_END(c) (vga_get_crtc(c, VGA_CRTC_VDE) \
+ (((vga_get_crtc(c, VGA_CRTC_OVFL_REG) >> \
@@ -76,66 +89,63 @@ unsigned char VGA_ATR_TEXT[NUM_ATR_REG] = {
0x0c, 0x00, 0x0f, 0x08, 0x00 };
void
-vga_get_hardware_settings(struct vgaregmap *reg, int *width, int *height)
+vga_get_hardware_settings(vgaregmap_t reg, int *width, int *height)
{
*width = (GET_HORIZ_END(reg)+1)*8;
*height = GET_VERT_END(reg)+1;
if (GET_VERT_X2(reg)) *height *= 2;
}
-#define PUTB(reg, off, v) ddi_put8(reg->handle, reg->addr + (off), v)
-#define GETB(reg, off) ddi_get8(reg->handle, reg->addr + (off))
-
int
-vga_get_reg(struct vgaregmap *reg, int indexreg)
+vga_get_reg(vgaregmap_t reg, int indexreg)
{
return (GETB(reg, indexreg));
}
void
-vga_set_reg(struct vgaregmap *reg, int indexreg, int v)
+vga_set_reg(vgaregmap_t reg, int indexreg, int v)
{
PUTB(reg, indexreg, v);
}
int
-vga_get_crtc(struct vgaregmap *reg, int i)
+vga_get_crtc(vgaregmap_t reg, int i)
{
return (vga_get_indexed(reg, VGA_CRTC_ADR, VGA_CRTC_DATA, i));
}
void
-vga_set_crtc(struct vgaregmap *reg, int i, int v)
+vga_set_crtc(vgaregmap_t reg, int i, int v)
{
vga_set_indexed(reg, VGA_CRTC_ADR, VGA_CRTC_DATA, i, v);
}
int
-vga_get_seq(struct vgaregmap *reg, int i)
+vga_get_seq(vgaregmap_t reg, int i)
{
return (vga_get_indexed(reg, VGA_SEQ_ADR, VGA_SEQ_DATA, i));
}
void
-vga_set_seq(struct vgaregmap *reg, int i, int v)
+vga_set_seq(vgaregmap_t reg, int i, int v)
{
vga_set_indexed(reg, VGA_SEQ_ADR, VGA_SEQ_DATA, i, v);
}
int
-vga_get_grc(struct vgaregmap *reg, int i)
+vga_get_grc(vgaregmap_t reg, int i)
{
return (vga_get_indexed(reg, VGA_GRC_ADR, VGA_GRC_DATA, i));
}
void
-vga_set_grc(struct vgaregmap *reg, int i, int v)
+vga_set_grc(vgaregmap_t reg, int i, int v)
{
vga_set_indexed(reg, VGA_GRC_ADR, VGA_GRC_DATA, i, v);
}
int
-vga_get_atr(struct vgaregmap *reg, int i)
+vga_get_atr(vgaregmap_t reg, int i)
{
int ret;
@@ -150,7 +160,7 @@ vga_get_atr(struct vgaregmap *reg, int i)
}
void
-vga_set_atr(struct vgaregmap *reg, int i, int v)
+vga_set_atr(vgaregmap_t reg, int i, int v)
{
(void) GETB(reg, CGA_STAT);
PUTB(reg, VGA_ATR_AD, i);
@@ -162,7 +172,7 @@ vga_set_atr(struct vgaregmap *reg, int i, int v)
void
vga_set_indexed(
- struct vgaregmap *reg,
+ vgaregmap_t reg,
int indexreg,
int datareg,
unsigned char index,
@@ -174,7 +184,7 @@ vga_set_indexed(
int
vga_get_indexed(
- struct vgaregmap *reg,
+ vgaregmap_t reg,
int indexreg,
int datareg,
unsigned char index)
@@ -190,7 +200,7 @@ vga_get_indexed(
*/
void
vga_put_cmap(
- struct vgaregmap *reg,
+ vgaregmap_t reg,
int index,
unsigned char r,
unsigned char g,
@@ -205,7 +215,7 @@ vga_put_cmap(
void
vga_get_cmap(
- struct vgaregmap *reg,
+ vgaregmap_t reg,
int index,
unsigned char *r,
unsigned char *g,
@@ -220,8 +230,7 @@ vga_get_cmap(
#ifdef DEBUG
void
-vga_dump_regs(struct vgaregmap *reg,
- int maxseq, int maxcrtc, int maxatr, int maxgrc)
+vga_dump_regs(vgaregmap_t reg, int maxseq, int maxcrtc, int maxatr, int maxgrc)
{
int i, j;
diff --git a/usr/src/lib/libficl/Makefile.com b/usr/src/lib/libficl/Makefile.com
index a7f4a3f63f..b4532d2ed9 100644
--- a/usr/src/lib/libficl/Makefile.com
+++ b/usr/src/lib/libficl/Makefile.com
@@ -21,7 +21,7 @@ VERS=.$(MAJOR).$(MINOR)
OBJECTS= dictionary.o system.o fileaccess.o float.o double.o prefix.o search.o \
softcore.o stack.o tools.o vm.o primitives.o unix.o utility.o \
hash.o callback.o word.o loader.o pager.o extras.o \
- loader_emu.o lz4.o
+ loader_emu.o pnglite.o lz4.o
include $(SRC)/lib/Makefile.lib
@@ -29,17 +29,19 @@ LIBS= $(DYNLIB) $(LINTLIB)
FICLDIR= $(SRC)/common/ficl
CSTD= $(CSTD_GNU99)
+PNGLITE= $(SRC)/common/pnglite
CPPFLAGS += -I.. -I$(FICLDIR) -D_LARGEFILE64_SOURCE=1
+CPPFLAGS += -I$(PNGLITE)
# As variable "count" is marked volatile, gcc 4.4.4 will complain about
# function argument. So we switch this warning off
# for time being, till gcc 4.4.4 will be replaced.
pics/vm.o := CERRWARN += -_gcc=-Wno-clobbered
-LDLIBS += -luuid -lc -lm -lumem
+LDLIBS += -luuid -lz -lc -lm -lumem
HEADERS= $(FICLDIR)/ficl.h $(FICLDIR)/ficltokens.h ../ficllocal.h \
- $(FICLDIR)/ficlplatform/unix.h
+ $(FICLDIR)/ficlplatform/unix.h $(PNGLITE)/pnglite.h
pics/%.o: ../softcore/%.c $(HEADERS)
$(COMPILE.c) -o $@ $<
@@ -61,6 +63,10 @@ pics/%.o: $(FICLDIR)/softcore/%.c $(HEADERS)
$(COMPILE.c) -o $@ $<
$(POST_PROCESS_O)
+pics/%.o: $(PNGLITE)/%.c $(HEADERS)
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
$(LINTLIB) := SRCS= ../$(LINTSRC)
all: $(LIBS)
diff --git a/usr/src/man/man5/loader.5 b/usr/src/man/man5/loader.5
index 0b0a2b123a..69a9261747 100644
--- a/usr/src/man/man5/loader.5
+++ b/usr/src/man/man5/loader.5
@@ -95,8 +95,8 @@ Then, devices are probed,
and
.Va loaddev
are set, and
-.Va COLUMNS ,
-.Va LINES ,
+.Va screen-#cols ,
+.Va screen-#rows ,
and
.Va ISADIR
are set.
@@ -274,7 +274,7 @@ as the pool.
.Pp
.It Ic more Ar file Op Ar
Display the files specified, with a pause at each
-.Va LINES
+.Va screen-#rows
displayed.
.Pp
.It Ic read Xo
@@ -452,7 +452,7 @@ Syntax for devices is odd.
Has the value
.Dq Li ok
if the Forth's current state is interpreting.
-.It Va LINES
+.It Va screen-#rows
Define the number of lines on the screen, to be used by the pager.
.It Va module_path
Sets the list of directories which will be searched for modules
diff --git a/usr/src/pkg/manifests/system-boot-loader.mf b/usr/src/pkg/manifests/system-boot-loader.mf
index 22d5337392..d4508edfbc 100644
--- a/usr/src/pkg/manifests/system-boot-loader.mf
+++ b/usr/src/pkg/manifests/system-boot-loader.mf
@@ -71,6 +71,7 @@ $(i386_ONLY)file path=boot/forth/shortcuts.4th group=sys mode=0444
$(i386_ONLY)file path=boot/forth/support.4th group=sys mode=0444
$(i386_ONLY)file path=boot/forth/version.4th group=sys mode=0444
$(i386_ONLY)file path=boot/gptzfsboot group=sys mode=0444
+$(i386_ONLY)file path=boot/illumos.png group=sys mode=0444
$(i386_ONLY)file path=boot/loader group=sys mode=0444
$(i386_ONLY)file path=boot/loader.help group=sys mode=0444
$(i386_ONLY)file path=boot/loader.rc group=sys mode=0444
@@ -94,3 +95,5 @@ license lic_CDDL license=lic_CDDL
license usr/src/boot/COPYRIGHT license=usr/src/boot/COPYRIGHT
license usr/src/boot/sys/boot/common/linenoise/LICENSE \
license=usr/src/boot/sys/boot/common/linenoise/LICENSE
+license usr/src/common/pnglite/THIRDPARTYLICENSE \
+ license=usr/src/common/pnglite/THIRDPARTYLICENSE
diff --git a/usr/src/uts/common/Makefile.rules b/usr/src/uts/common/Makefile.rules
index 9bf6f18a26..3dceec9a52 100644
--- a/usr/src/uts/common/Makefile.rules
+++ b/usr/src/uts/common/Makefile.rules
@@ -90,7 +90,7 @@ $(OBJS_DIR)/%.o: $(COMMONBASE)/mpi/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
-$(OBJS_DIR)/%.o: $(COMMONBASE)/acl/%.c
+$(OBJS_DIR)/%.o: $(COMMONBASE)/acl/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
@@ -283,6 +283,10 @@ $(OBJS_DIR)/%.o: $(COMMONBASE)/smbsrv/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
+$(OBJS_DIR)/%.o: $(COMMONBASE)/vga/%.c
+ $(COMPILE.c) -o $@ $<
+ $(CTFCONVERT_O)
+
$(OBJS_DIR)/%.o: $(UTSBASE)/common/fs/smbsrv/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
@@ -1916,7 +1920,7 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/common/inet/ip/%.c
$(LINTS_DIR)/%.ln: $(UTSBASE)/common/inet/ipnet/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
-$(LINTS_DIR)/%.ln: $(UTSBASE)/common/inet/iptun/%.c
+$(LINTS_DIR)/%.ln: $(UTSBASE)/common/inet/iptun/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
$(LINTS_DIR)/%.ln: $(UTSBASE)/common/inet/ipd/%.c
diff --git a/usr/src/uts/common/sys/consplat.h b/usr/src/uts/common/sys/consplat.h
index a9f6fe9633..d602c0875d 100644
--- a/usr/src/uts/common/sys/consplat.h
+++ b/usr/src/uts/common/sys/consplat.h
@@ -43,6 +43,7 @@ extern char *plat_stdoutpath(void);
extern char *plat_diagpath(void);
extern int plat_stdin_is_keyboard(void);
extern int plat_stdout_is_framebuffer(void);
+extern void plat_tem_get_colors(uint8_t *, uint8_t *);
extern void plat_tem_get_inverses(int *, int *);
extern void plat_tem_get_prom_font_size(int *, int *);
extern void plat_tem_get_prom_size(size_t *, size_t *);
diff --git a/usr/src/uts/common/sys/vgareg.h b/usr/src/uts/common/sys/vgareg.h
index 3a2885a34b..230e9e1b2e 100644
--- a/usr/src/uts/common/sys/vgareg.h
+++ b/usr/src/uts/common/sys/vgareg.h
@@ -27,12 +27,16 @@
#ifndef _SYS_VGAREG_H
#define _SYS_VGAREG_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
+#define VGA_REG_ADDR 0x3c0
+#define VGA_REG_SIZE 0x20
+
+#define VGA_MEM_ADDR 0xa0000
+#define VGA_MEM_SIZE 0x20000
+
/*
* VGA frame buffer hardware definitions.
*/
diff --git a/usr/src/uts/common/sys/vgasubr.h b/usr/src/uts/common/sys/vgasubr.h
index bb266643b0..448079437c 100644
--- a/usr/src/uts/common/sys/vgasubr.h
+++ b/usr/src/uts/common/sys/vgasubr.h
@@ -27,42 +27,49 @@
#ifndef _SYS_VGASUBR_H
#define _SYS_VGASUBR_H
-#pragma ident "%Z%%M% %I% %E% SMI" /* SunOS4.1 1.11 */
-
#ifdef __cplusplus
extern "C" {
#endif
+#ifdef _KERNEL
+
struct vgaregmap {
uint8_t *addr;
ddi_acc_handle_t handle;
boolean_t mapped;
};
+typedef struct vgaregmap *vgaregmap_t;
+
+#elif defined(_STANDALONE)
+
+typedef uint_t vgaregmap_t;
+
+#endif
-extern int vga_get_reg(struct vgaregmap *reg, int i);
-extern void vga_set_reg(struct vgaregmap *reg, int i, int v);
-extern int vga_get_crtc(struct vgaregmap *reg, int i);
-extern void vga_set_crtc(struct vgaregmap *reg, int i, int v);
-extern int vga_get_seq(struct vgaregmap *reg, int i);
-extern void vga_set_seq(struct vgaregmap *reg, int i, int v);
-extern int vga_get_grc(struct vgaregmap *reg, int i);
-extern void vga_set_grc(struct vgaregmap *reg, int i, int v);
-extern int vga_get_atr(struct vgaregmap *reg, int i);
-extern void vga_set_atr(struct vgaregmap *reg, int i, int v);
-extern void vga_put_cmap(struct vgaregmap *reg,
+extern int vga_get_reg(vgaregmap_t reg, int i);
+extern void vga_set_reg(vgaregmap_t reg, int i, int v);
+extern int vga_get_crtc(vgaregmap_t reg, int i);
+extern void vga_set_crtc(vgaregmap_t reg, int i, int v);
+extern int vga_get_seq(vgaregmap_t reg, int i);
+extern void vga_set_seq(vgaregmap_t reg, int i, int v);
+extern int vga_get_grc(vgaregmap_t reg, int i);
+extern void vga_set_grc(vgaregmap_t reg, int i, int v);
+extern int vga_get_atr(vgaregmap_t reg, int i);
+extern void vga_set_atr(vgaregmap_t reg, int i, int v);
+extern void vga_put_cmap(vgaregmap_t reg,
int index, unsigned char r, unsigned char g, unsigned char b);
-extern void vga_get_cmap(struct vgaregmap *reg,
+extern void vga_get_cmap(vgaregmap_t reg,
int index, unsigned char *r, unsigned char *g, unsigned char *b);
-extern void vga_get_hardware_settings(struct vgaregmap *reg,
+extern void vga_get_hardware_settings(vgaregmap_t reg,
int *width, int *height);
-extern void vga_set_indexed(struct vgaregmap *reg, int indexreg,
+extern void vga_set_indexed(vgaregmap_t reg, int indexreg,
int datareg, unsigned char index, unsigned char val);
-extern int vga_get_indexed(struct vgaregmap *reg, int indexreg,
+extern int vga_get_indexed(vgaregmap_t reg, int indexreg,
int datareg, unsigned char index);
#define VGA_MISC_TEXT 0x67
#define NUM_CRTC_REG 25
-#define NUM_SEQ_REG 5
+#define NUM_SEQ_REG 5
#define NUM_GRC_REG 9
#define NUM_ATR_REG 21
@@ -73,7 +80,7 @@ extern unsigned char VGA_GRC_TEXT[NUM_GRC_REG];
extern unsigned char VGA_TEXT_PALETTES[64][3];
#if defined(DEBUG)
-extern void vga_dump_regs(struct vgaregmap *reg,
+extern void vga_dump_regs(vgaregmap_t reg,
int maxseq, int maxcrtc, int maxatr, int maxgrc);
#endif
diff --git a/usr/src/uts/common/sys/visual_io.h b/usr/src/uts/common/sys/visual_io.h
index db0acdda50..0194d00206 100644
--- a/usr/src/uts/common/sys/visual_io.h
+++ b/usr/src/uts/common/sys/visual_io.h
@@ -27,8 +27,6 @@
#ifndef _SYS_VISUAL_IO_H
#define _SYS_VISUAL_IO_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -140,7 +138,7 @@ struct vis_cmap {
};
-#ifdef _KERNEL
+#if defined(_KERNEL) || defined(_STANDALONE)
/*
* The following ioctls are used for communication between the layered
* device and the framebuffer. The layered driver calls the framebuffer
@@ -164,10 +162,11 @@ typedef short screen_size_t;
* Union of pixel depths
*/
typedef union {
- unsigned char mono; /* one-bit */
- unsigned char four; /* four bit */
- unsigned char eight; /* eight bit */
- unsigned char twentyfour[3]; /* 24 bit */
+ unsigned char mono; /* one-bit */
+ unsigned char four; /* four bit */
+ unsigned char eight; /* eight bit */
+ unsigned char sixteen[2]; /* 16 bit */
+ unsigned char twentyfour[3]; /* 24 bit */
} color_t;
/*
@@ -179,7 +178,7 @@ typedef union {
* ioctl(fd, VIS_DEVINIT, struct vis_devinit *)
*/
#define VIS_DEVINIT (VIOC|1)
-#define VIS_CONS_REV 3 /* Console IO interface version */
+#define VIS_CONS_REV 4 /* Console IO interface version */
/* Modes */
#define VIS_TEXT 0 /* Use text mode when displaying data */
#define VIS_PIXEL 1 /* Use pixel mode when displaying data */
@@ -229,6 +228,18 @@ typedef union {
*/
#define VIS_CONSCOPY (VIOC|7)
+/*
+ * VIS_CONSCLEAR:
+ * Clear the screen using provided color. Used on VIS_PIXEL mode.
+ *
+ * ioctl(fd, VIS_CONSCLEAR, struct vis_consclear *)
+ */
+#define VIS_CONSCLEAR (VIOC|8)
+
+struct vis_consclear {
+ unsigned char bg_color; /* Background color */
+};
+
struct vis_consdisplay {
screen_pos_t row; /* Row to display data at */
screen_pos_t col; /* Col to display data at */
@@ -284,6 +295,8 @@ struct vis_devinit; /* forward decl. for typedef */
typedef void (*vis_modechg_cb_t)(struct vis_modechg_arg *,
struct vis_devinit *);
+typedef uint32_t (*color_map_fn_t)(uint8_t color);
+
struct vis_devinit {
/*
* This set of fields are used as parameters passed from the
@@ -294,6 +307,7 @@ struct vis_devinit {
screen_size_t height; /* Height of the device */
screen_size_t linebytes; /* Bytes per scan line */
int depth; /* Device depth */
+ color_map_fn_t color_map; /* Color map tem -> fb */
short mode; /* Mode to use when displaying data */
struct vis_polledio *polledio; /* Polled output routines */
@@ -305,7 +319,18 @@ struct vis_devinit {
struct vis_modechg_arg *modechg_arg; /* Mode change cb arg */
};
-#endif /* _KERNEL */
+struct visual_ops {
+ const struct vis_identifier *ident;
+ int (*kdsetmode)(int);
+ int (*devinit)(struct vis_devinit *);
+ void (*cons_copy)(struct vis_conscopy *);
+ void (*cons_display)(struct vis_consdisplay *);
+ void (*cons_cursor)(struct vis_conscursor *);
+ int (*cons_clear)(struct vis_consclear *);
+ int (*cons_put_cmap)(struct vis_cmap *);
+};
+
+#endif /* _KERNEL || _STANDALONE */
#ifdef __cplusplus
}