diff options
author | Toomas Soome <tsoome@me.com> | 2018-12-01 22:31:08 +0200 |
---|---|---|
committer | Hans Rosenfeld <hans.rosenfeld@joyent.com> | 2019-01-07 10:11:18 +0100 |
commit | 9890ff8357a674572254e0be06b175a1e8eab4b0 (patch) | |
tree | 3b4b3a2b61f0cd74bd99b547f6e87c2688b4e122 | |
parent | f33b666290305a2b2c134d23cbd1e70e06bf36fd (diff) | |
download | illumos-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>
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 Binary files differnew file mode 100644 index 0000000000..3af7a2f360 --- /dev/null +++ b/usr/src/boot/sys/boot/forth/illumos.png 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 } |