summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJerry Jelinek <jerry.jelinek@joyent.com>2019-01-25 13:15:50 +0000
committerJerry Jelinek <jerry.jelinek@joyent.com>2019-01-25 13:15:50 +0000
commit5d687f5a37b08ffb3af39f1fc475eba83078c761 (patch)
treec13f03cf095cdb500c0e65e55da28f6d234af830
parentce6a7649078ae9f0ae246da1fffb1343093388f2 (diff)
parent8e6d016f3eedbcabf3a3bc35224bca733dc405a4 (diff)
downloadillumos-joyent-5d687f5a37b08ffb3af39f1fc475eba83078c761.tar.gz
[illumos-gate merge]
commit 8e6d016f3eedbcabf3a3bc35224bca733dc405a4 10234 uts: early start frame buffer console support commit a016ad93bcf2a20e416da9f44cd299eb19ab4c08 10274 Some files built but not packaged on sparc commit 0d640b6ed315cfedad6977d67f8dea20725d0b8d 10273 smatch should be corrected in exception_lists/packaging for sparc commit 5352b2e7bbd3672bcc15645d9b8d18b207a3bfcc 10272 Manual pages added in 10212 should have been i386 only commit 421a607f20240b957c77d8a5a6d34f13da0efb1e 10118 libeti() NULL check after deref Conflicts: usr/src/cmd/Makefile
-rw-r--r--exception_lists/packaging4
-rw-r--r--usr/src/cmd/Makefile5
-rw-r--r--usr/src/lib/libeti/form/common/field.c13
-rw-r--r--usr/src/man/man5/Makefile3
-rw-r--r--usr/src/man/man7d/Makefile3
-rw-r--r--usr/src/pkg/manifests/diagnostic-cpu-counters.mf40
-rw-r--r--usr/src/uts/common/sys/vgareg.h28
-rw-r--r--usr/src/uts/i86pc/Makefile.files1
-rw-r--r--usr/src/uts/i86pc/boot/boot_console.c214
-rw-r--r--usr/src/uts/i86pc/boot/boot_console_impl.h44
-rw-r--r--usr/src/uts/i86pc/boot/boot_fb.c700
-rw-r--r--usr/src/uts/i86pc/boot/boot_vga.c102
-rw-r--r--usr/src/uts/i86pc/boot/boot_vga.h57
-rw-r--r--usr/src/uts/i86pc/dboot/dboot_startkern.c66
-rw-r--r--usr/src/uts/i86pc/os/fakebop.c6
-rw-r--r--usr/src/uts/i86pc/sys/boot_console.h3
-rw-r--r--usr/src/uts/i86pc/sys/framebuffer.h91
-rw-r--r--usr/src/uts/i86pc/sys/rgb.h44
-rw-r--r--usr/src/uts/i86xpv/Makefile.files1
19 files changed, 1265 insertions, 160 deletions
diff --git a/exception_lists/packaging b/exception_lists/packaging
index 35349e92a5..aa6f585142 100644
--- a/exception_lists/packaging
+++ b/exception_lists/packaging
@@ -29,6 +29,7 @@
# Copyright 2017 RackTop Systems.
# Copyright 2019, Joyent, Inc.
# Copyright 2018 Jason King
+# Copyright 2019 Peter Tribble
#
#
@@ -1026,4 +1027,5 @@ lib/llib-lcustr.ln
# smatch is delivered and used only with the source tree
#
opt/onbld/bin/i386/smatch i386
-opt/onbld/share/smatch i386
+opt/onbld/bin/sparc/smatch sparc
+opt/onbld/share/smatch
diff --git a/usr/src/cmd/Makefile b/usr/src/cmd/Makefile
index 8d16ccf158..0f7d4ad1ad 100644
--- a/usr/src/cmd/Makefile
+++ b/usr/src/cmd/Makefile
@@ -28,6 +28,7 @@
# Copyright 2016 Toomas Soome <tsoome@me.com>
# Copyright 2018 Nexenta Systems, Inc.
# Copyright 2018 Gary Mills
+# Copyright 2019 Peter Tribble
#
include ../Makefile.master
@@ -61,7 +62,6 @@ COMMON_SUBDIRS= \
adbgen \
acct \
acctadm \
- ahciem \
arch \
asa \
ast \
@@ -113,7 +113,6 @@ COMMON_SUBDIRS= \
ctrun \
ctstat \
ctwatch \
- cxgbetool \
datadm \
date \
dc \
@@ -483,9 +482,11 @@ i386_SUBDIRS= \
acpi \
acpihpd \
addbadsec \
+ ahciem \
bhyve \
bhyvectl \
biosdev \
+ cxgbetool \
diskscan \
nvmeadm \
rtc \
diff --git a/usr/src/lib/libeti/form/common/field.c b/usr/src/lib/libeti/form/common/field.c
index 767ce7d525..c39c9db62d 100644
--- a/usr/src/lib/libeti/form/common/field.c
+++ b/usr/src/lib/libeti/form/common/field.c
@@ -28,7 +28,9 @@
* All rights reserved.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright (c) 2018, Joyent, Inc.
+ */
/*LINTLIBRARY*/
@@ -337,9 +339,14 @@ field_info(FIELD *f, int *rows, int *cols, int *frow, int *fcol,
int
set_max_field(FIELD *f, int max)
{
- BOOLEAN onerow = OneRow(f);
+ BOOLEAN onerow;
+
+ if (f == NULL)
+ return (E_BAD_ARGUMENT);
+
+ onerow = OneRow(f);
- if (!f || max && ((onerow && f->dcols > max) ||
+ if (max && ((onerow && f->dcols > max) ||
(!onerow && f->drows > max)))
return (E_BAD_ARGUMENT);
diff --git a/usr/src/man/man5/Makefile b/usr/src/man/man5/Makefile
index 18d2d6606f..471bd3641e 100644
--- a/usr/src/man/man5/Makefile
+++ b/usr/src/man/man5/Makefile
@@ -17,6 +17,7 @@
# Copyright 2016, Joyent, Inc.
# Copyright 2018 Gary Mills
# Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
+# Copyright 2019 Peter Tribble
#
include $(SRC)/Makefile.master
@@ -64,7 +65,6 @@ _MANFILES= Intro.5 \
inotify.5 \
ipfilter.5 \
isalist.5 \
- isoboot.5 \
kerberos.5 \
krb5_auth_rules.5 \
krb5envvar.5 \
@@ -145,6 +145,7 @@ i386_MANFILES= beastie.4th.5 \
color.4th.5 \
delay.4th.5 \
gptzfsboot.5 \
+ isoboot.5 \
loader.5 \
loader.4th.5 \
menu.4th.5 \
diff --git a/usr/src/man/man7d/Makefile b/usr/src/man/man7d/Makefile
index 5775f8a754..dc4a9d8dbf 100644
--- a/usr/src/man/man7d/Makefile
+++ b/usr/src/man/man7d/Makefile
@@ -15,6 +15,7 @@
# Copyright (c) 2017, Joyent, Inc.
# Copyright 2016 Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
# Copyright 2018 Nexenta Systems, Inc.
+# Copyright 2019 Peter Tribble
#
include $(SRC)/Makefile.master
@@ -102,7 +103,6 @@ _MANFILES= aac.7d \
ptm.7d \
pts.7d \
pty.7d \
- qede.7d \
qlc.7d \
ramdisk.7d \
random.7d \
@@ -223,6 +223,7 @@ i386_MANFILES= ahci.7d \
nv_sata.7d \
nvme.7d \
pcn.7d \
+ qede.7d \
radeon.7d \
ral.7d \
rtw.7d \
diff --git a/usr/src/pkg/manifests/diagnostic-cpu-counters.mf b/usr/src/pkg/manifests/diagnostic-cpu-counters.mf
index 11616bf91d..e6c5fbb3ae 100644
--- a/usr/src/pkg/manifests/diagnostic-cpu-counters.mf
+++ b/usr/src/pkg/manifests/diagnostic-cpu-counters.mf
@@ -71,10 +71,10 @@ file path=usr/lib/llib-lpctx.ln
file path=usr/sbin/cpustat mode=0555
file path=usr/share/man/man1/cputrack.1
file path=usr/share/man/man1m/cpustat.1m
-file path=usr/share/man/man3cpc/bdw_de_events.3cpc
-file path=usr/share/man/man3cpc/bdw_events.3cpc
-file path=usr/share/man/man3cpc/bdx_events.3cpc
-file path=usr/share/man/man3cpc/bnl_events.3cpc
+$(i386_ONLY)file path=usr/share/man/man3cpc/bdw_de_events.3cpc
+$(i386_ONLY)file path=usr/share/man/man3cpc/bdw_events.3cpc
+$(i386_ONLY)file path=usr/share/man/man3cpc/bdx_events.3cpc
+$(i386_ONLY)file path=usr/share/man/man3cpc/bnl_events.3cpc
file path=usr/share/man/man3cpc/cpc.3cpc
file path=usr/share/man/man3cpc/cpc_access.3cpc
file path=usr/share/man/man3cpc/cpc_bind_curlwp.3cpc
@@ -95,24 +95,24 @@ file path=usr/share/man/man3cpc/cpc_shared_open.3cpc
file path=usr/share/man/man3cpc/cpc_strtoevent.3cpc
file path=usr/share/man/man3cpc/cpc_version.3cpc
file path=usr/share/man/man3cpc/generic_events.3cpc
-file path=usr/share/man/man3cpc/glm_events.3cpc
-file path=usr/share/man/man3cpc/glp_events.3cpc
-file path=usr/share/man/man3cpc/hsw_events.3cpc
-file path=usr/share/man/man3cpc/hsx_events.3cpc
-file path=usr/share/man/man3cpc/ivb_events.3cpc
-file path=usr/share/man/man3cpc/ivt_events.3cpc
-file path=usr/share/man/man3cpc/jkt_events.3cpc
-file path=usr/share/man/man3cpc/nhm_ep_events.3cpc
-file path=usr/share/man/man3cpc/nhm_ex_events.3cpc
+$(i386_ONLY)file path=usr/share/man/man3cpc/glm_events.3cpc
+$(i386_ONLY)file path=usr/share/man/man3cpc/glp_events.3cpc
+$(i386_ONLY)file path=usr/share/man/man3cpc/hsw_events.3cpc
+$(i386_ONLY)file path=usr/share/man/man3cpc/hsx_events.3cpc
+$(i386_ONLY)file path=usr/share/man/man3cpc/ivb_events.3cpc
+$(i386_ONLY)file path=usr/share/man/man3cpc/ivt_events.3cpc
+$(i386_ONLY)file path=usr/share/man/man3cpc/jkt_events.3cpc
+$(i386_ONLY)file path=usr/share/man/man3cpc/nhm_ep_events.3cpc
+$(i386_ONLY)file path=usr/share/man/man3cpc/nhm_ex_events.3cpc
file path=usr/share/man/man3cpc/pctx_capture.3cpc
file path=usr/share/man/man3cpc/pctx_set_events.3cpc
-file path=usr/share/man/man3cpc/skl_events.3cpc
-file path=usr/share/man/man3cpc/skx_events.3cpc
-file path=usr/share/man/man3cpc/slm_events.3cpc
-file path=usr/share/man/man3cpc/snb_events.3cpc
-file path=usr/share/man/man3cpc/wsm_ep_dp_events.3cpc
-file path=usr/share/man/man3cpc/wsm_ep_sp_events.3cpc
-file path=usr/share/man/man3cpc/wsm_ex_events.3cpc
+$(i386_ONLY)file path=usr/share/man/man3cpc/skl_events.3cpc
+$(i386_ONLY)file path=usr/share/man/man3cpc/skx_events.3cpc
+$(i386_ONLY)file path=usr/share/man/man3cpc/slm_events.3cpc
+$(i386_ONLY)file path=usr/share/man/man3cpc/snb_events.3cpc
+$(i386_ONLY)file path=usr/share/man/man3cpc/wsm_ep_dp_events.3cpc
+$(i386_ONLY)file path=usr/share/man/man3cpc/wsm_ep_sp_events.3cpc
+$(i386_ONLY)file path=usr/share/man/man3cpc/wsm_ex_events.3cpc
file path=usr/share/man/man3lib/libcpc.3lib
file path=usr/share/man/man3lib/libpctx.3lib
hardlink path=usr/bin/cputrack target=../lib/isaexec
diff --git a/usr/src/uts/common/sys/vgareg.h b/usr/src/uts/common/sys/vgareg.h
index 230e9e1b2e..1626a45a84 100644
--- a/usr/src/uts/common/sys/vgareg.h
+++ b/usr/src/uts/common/sys/vgareg.h
@@ -37,6 +37,9 @@ extern "C" {
#define VGA_MEM_ADDR 0xa0000
#define VGA_MEM_SIZE 0x20000
+#define VGA_TEXT_COLS 80
+#define VGA_TEXT_ROWS 25
+
/*
* VGA frame buffer hardware definitions.
*/
@@ -86,6 +89,8 @@ extern "C" {
#define VGA_MISC_PGSL 0x20
#define VGA_MISC_HSP 0x40
#define VGA_MISC_VSP 0x80
+#define VGA_MISC_IS1_VR 0x08 /* Vertical Retrace */
+#define VGA_MISC_IS1_DD 0x01 /* Display Disabled */
/*
* CRT Controller registers
@@ -177,6 +182,11 @@ extern "C" {
#define VGA_SEQ_CLK_MODE_8DC 0x01
#define VGA_SEQ_EN_WT_PL 0x02
#define VGA_SEQ_EN_WT_PL_ALL 0x0f
+#define VGA_SEQ_CMS 0x03 /* Char Map Select */
+#define VGA_SEQ_CMS_SAH 0x20 /* Char. A (bit 2) */
+#define VGA_SEQ_CMS_SBH 0x10 /* Char. B (bit 2) */
+#define VGA_SEQ_CMS_SA 0x0C /* Char. A (bit 0+1) */
+#define VGA_SEQ_CMS_SB 0x03 /* Char. B (bit 0+1) */
#define VGA_SEQ_MEM_MODE 0x04
#define VGA_SEQ_MEM_MODE_EXT_MEM 0x02
#define VGA_SEQ_MEM_MODE_SEQ_MODE 0x04
@@ -202,13 +212,17 @@ extern "C" {
/*
* Attribute controller registers
*/
-#define VGA_ATR_PLT_REG 0x00
-#define VGA_ATR_NUM_PLT 0x10
-#define VGA_ATR_MODE 0x10
-#define VGA_ATR_MODE_GRAPH 0x01
-#define VGA_ATR_MODE_9WIDE 0x04
-#define VGA_ATR_MODE_BLINK 0x08
-#define VGA_ATR_MODE_256CLR 0x40
+#define VGA_ATR_PAS 0x20 /* Palette Address Source */
+#define VGA_ATR_PLT_REG 0x00 /* Palette Register */
+#define VGA_ATR_NUM_PLT 0x10 /* Palette Register count */
+#define VGA_ATR_MODE 0x10 /* Attribute mode control */
+#define VGA_ATR_MODE_GRAPH 0x01 /* Graphics enable */
+#define VGA_ATR_MODE_MONO 0x02 /* Monochrome emulation */
+#define VGA_ATR_MODE_9WIDE 0x04 /* Line Graphics enable */
+#define VGA_ATR_MODE_BLINK 0x08 /* Blink enable */
+#define VGA_ATR_MODE_PPM 0x20 /* Pixel panning mode */
+#define VGA_ATR_MODE_256CLR 0x40 /* 8-bit color enable */
+#define VGA_ATR_MODE_P54S 0x80 /* Palette bits 4-5 select */
#define VGA_ATR_BDR_CLR 0x11
#define VGA_ATR_DISP_PLN 0x12
#define VGA_ATR_DISP_PLN_ALL 0x0f
diff --git a/usr/src/uts/i86pc/Makefile.files b/usr/src/uts/i86pc/Makefile.files
index 1292c81e9c..db2472d773 100644
--- a/usr/src/uts/i86pc/Makefile.files
+++ b/usr/src/uts/i86pc/Makefile.files
@@ -142,6 +142,7 @@ BOOT_DRIVER_OBJS = \
boot_keyboard.o \
boot_keyboard_table.o \
boot_vga.o \
+ boot_fb.o \
boot_mmu.o \
dboot_multiboot2.o \
$(FONT_OBJS)
diff --git a/usr/src/uts/i86pc/boot/boot_console.c b/usr/src/uts/i86pc/boot/boot_console.c
index e5d8e73597..b1f1a31b3b 100644
--- a/usr/src/uts/i86pc/boot/boot_console.c
+++ b/usr/src/uts/i86pc/boot/boot_console.c
@@ -28,15 +28,18 @@
#include <sys/types.h>
#include <sys/systm.h>
#include <sys/archsystm.h>
+#include <sys/framebuffer.h>
#include <sys/boot_console.h>
#include <sys/panic.h>
#include <sys/ctype.h>
+#include <sys/ascii.h>
+#include <sys/vgareg.h>
#if defined(__xpv)
#include <sys/hypervisor.h>
#endif /* __xpv */
+#include "boot_console_impl.h"
#include "boot_serial.h"
-#include "boot_vga.h"
#if defined(_BOOT)
#include <dboot/dboot_asm.h>
@@ -57,6 +60,7 @@ extern int bcons_getchar_xen(void);
extern int bcons_ischar_xen(void);
#endif /* __xpv */
+fb_info_t fb_info;
static int cons_color = CONS_COLOR;
static int console = CONS_SCREEN_TEXT;
static int diag = CONS_INVALID;
@@ -93,22 +97,6 @@ console_hypervisor_dev_type(int *tnum)
}
#endif /* __xpv */
-/* Clear the screen and initialize VIDEO, XPOS and YPOS. */
-void
-clear_screen(void)
-{
- /*
- * XXX should set vga mode so we don't depend on the
- * state left by the boot loader. Note that we have to
- * enable the cursor before clearing the screen since
- * the cursor position is dependant upon the cursor
- * skew, which is initialized by vga_cursor_display()
- */
- vga_cursor_display();
- vga_clear(cons_color);
- vga_setpos(0, 0);
-}
-
/* Put the character C on the screen. */
static void
screen_putchar(int c)
@@ -202,15 +190,6 @@ serial_init(void)
/* adjust setting based on tty properties */
serial_adjust_prop();
-
-#if defined(_BOOT)
- /*
- * Do a full reset to match console behavior.
- * 0x1B + c - reset everything
- */
- serial_putchar(0x1B);
- serial_putchar('c');
-#endif
}
/* Advance str pointer past white space */
@@ -608,6 +587,167 @@ bcons_init_env(struct xboot_info *xbi)
boot_env.be_size = modules[i].bm_size;
}
+int
+boot_fb(struct xboot_info *xbi, int console)
+{
+ if (xbi_fb_init(xbi) == B_FALSE)
+ return (console);
+
+ /* FB address is not set, fall back to serial terminal. */
+ if (fb_info.paddr == 0) {
+ return (CONS_TTY);
+ }
+
+ fb_info.terminal.x = 80;
+ fb_info.terminal.y = 34;
+ boot_fb_init(CONS_FRAMEBUFFER);
+
+ if (console == CONS_SCREEN_TEXT)
+ return (CONS_FRAMEBUFFER);
+ return (console);
+}
+
+/*
+ * TODO.
+ * quick and dirty local atoi. Perhaps should build with strtol, but
+ * dboot & early boot mix does overcomplicate things much.
+ * Stolen from libc anyhow.
+ */
+static int
+atoi(const char *p)
+{
+ int n, c, neg = 0;
+ unsigned char *up = (unsigned char *)p;
+
+ if (!isdigit(c = *up)) {
+ while (isspace(c))
+ c = *++up;
+ switch (c) {
+ case '-':
+ neg++;
+ /* FALLTHROUGH */
+ case '+':
+ c = *++up;
+ }
+ if (!isdigit(c))
+ return (0);
+ }
+ for (n = '0' - c; isdigit(c = *++up); ) {
+ n *= 10; /* two steps to avoid unnecessary overflow */
+ n += '0' - c; /* accum neg to avoid surprises at MAX */
+ }
+ return (neg ? n : -n);
+}
+
+static int
+set_vga_color(void)
+{
+ int color;
+ uint8_t tmp;
+/* BEGIN CSTYLED */
+/* Bk Rd Gr Br Bl Mg Cy Wh */
+ uint8_t dim_xlate[] = { 1, 5, 3, 7, 2, 6, 4, 8 };
+ uint8_t brt_xlate[] = { 9, 13, 11, 15, 10, 14, 12, 0 };
+ uint8_t solaris_color_to_pc_color[16] = {
+ 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
+ };
+/* END CSTYLED */
+
+ /*
+ * Now we have two principal cases, black on white and white on black.
+ * And we have possible inverse to switch them, and we want to
+ * follow the tem logic to set VGA TEXT color. FB will take care
+ * of itself in boot_fb.c
+ */
+ if (fb_info.inverse == B_TRUE ||
+ fb_info.inverse_screen == B_TRUE) {
+ tmp = dim_xlate[fb_info.fg_color];
+ color = solaris_color_to_pc_color[tmp] << 4;
+ tmp = brt_xlate[fb_info.bg_color];
+ color |= solaris_color_to_pc_color[tmp];
+ return (color);
+ }
+
+ /* use bright white for background */
+ if (fb_info.bg_color == 7)
+ tmp = brt_xlate[fb_info.bg_color];
+ else
+ tmp = dim_xlate[fb_info.bg_color];
+
+ color = solaris_color_to_pc_color[tmp] << 4;
+ tmp = dim_xlate[fb_info.fg_color];
+ color |= solaris_color_to_pc_color[tmp];
+ return (color);
+}
+
+static void
+bcons_init_fb(void)
+{
+ const char *propval;
+ int intval;
+
+ /* initialize with explicit default values */
+ fb_info.fg_color = CONS_COLOR;
+ fb_info.bg_color = 0;
+ fb_info.inverse = B_FALSE;
+ fb_info.inverse_screen = B_FALSE;
+
+ /* color values are 0 - 7 */
+ propval = find_boot_prop("tem.fg_color");
+ if (propval != NULL) {
+ intval = atoi(propval);
+ if (intval >= 0 && intval <= 7)
+ fb_info.fg_color = intval;
+ }
+
+ /* color values are 0 - 7 */
+ propval = find_boot_prop("tem.bg_color");
+ if (propval != NULL && ISDIGIT(*propval)) {
+ intval = atoi(propval);
+ if (intval >= 0 && intval <= 7)
+ fb_info.bg_color = intval;
+ }
+
+ /* get inverses. allow 0, 1, true, false */
+ propval = find_boot_prop("tem.inverse");
+ if (propval != NULL) {
+ if (*propval == '1' || MATCHES(propval, "true"))
+ fb_info.inverse = B_TRUE;
+ }
+
+ propval = find_boot_prop("tem.inverse-screen");
+ if (propval != NULL) {
+ if (*propval == '1' || MATCHES(propval, "true"))
+ fb_info.inverse_screen = B_TRUE;
+ }
+
+#if defined(_BOOT) && defined(_NEWFONT)
+ /*
+ * Load cursor position from bootloader only in dboot,
+ * dboot will pass cursor position to kernel via xboot info.
+ */
+ /*
+ * To keep consistent console, we reset boot screen till new fonts
+ * are available.
+ */
+ propval = find_boot_prop("tem.cursor.row");
+ if (propval != NULL) {
+ intval = atoi(propval);
+ if (intval >= 0 && intval <= 0xFFFF)
+ fb_info.cursor.pos.y = intval;
+ }
+
+ propval = find_boot_prop("tem.cursor.col");
+ if (propval != NULL) {
+ intval = atoi(propval);
+ if (intval >= 0 && intval <= 0xFFFF)
+ fb_info.cursor.pos.x = intval;
+ }
+#endif
+
+ cons_color = set_vga_color();
+}
+
/*
* Go through the console_devices array trying to match the string
* we were given. The string on the command line must end with
@@ -665,6 +805,9 @@ bcons_init(struct xboot_info *xbi)
bcons_init_env(xbi);
console = CONS_INVALID;
+ /* set up initial fb_info */
+ bcons_init_fb();
+
#if defined(__xpv)
bcons_init_xen(boot_line);
#endif /* __xpv */
@@ -745,6 +888,8 @@ bcons_init(struct xboot_info *xbi)
}
#endif /* __xpv */
+ /* make sure the FB is set up if present */
+ console = boot_fb(xbi, console);
switch (console) {
case CONS_TTY:
serial_init();
@@ -765,10 +910,9 @@ bcons_init(struct xboot_info *xbi)
kb_init();
break;
case CONS_SCREEN_TEXT:
+ boot_vga_init(cons_color);
+ /* Fall through */
default:
-#if defined(_BOOT)
- clear_screen(); /* clears the grub or xen screen */
-#endif /* _BOOT */
kb_init();
break;
}
@@ -964,6 +1108,9 @@ _doputchar(int device, int c)
case CONS_SCREEN_TEXT:
screen_putchar(c);
return;
+ case CONS_FRAMEBUFFER:
+ boot_fb_putchar(c);
+ return;
case CONS_SCREEN_GRAPHICS:
#if !defined(_BOOT)
case CONS_USBSER:
@@ -996,12 +1143,13 @@ bcons_putchar(int c)
return;
} else if (c == '\n' || c == '\r') {
bhcharpos = 0;
- _doputchar(console, '\r');
- _doputchar(console, c);
- if (diag != console) {
+ if (console != CONS_FRAMEBUFFER)
+ _doputchar(console, '\r');
+ if (diag != console && diag != CONS_FRAMEBUFFER)
_doputchar(diag, '\r');
+ _doputchar(console, c);
+ if (diag != console)
_doputchar(diag, c);
- }
return;
} else if (c == '\b') {
if (bhcharpos)
diff --git a/usr/src/uts/i86pc/boot/boot_console_impl.h b/usr/src/uts/i86pc/boot/boot_console_impl.h
new file mode 100644
index 0000000000..22caf4da8f
--- /dev/null
+++ b/usr/src/uts/i86pc/boot/boot_console_impl.h
@@ -0,0 +1,44 @@
+/*
+ * 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 <tsome@me.com>
+ */
+
+#include <sys/types.h>
+#include <sys/bootinfo.h>
+
+#ifndef _BOOT_CONSOLE_IMPL_H
+#define _BOOT_CONSOLE_IMPL_H
+
+/*
+ * Boot console implementation details.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern boolean_t xbi_fb_init(struct xboot_info *);
+extern void boot_fb_init(int);
+extern void boot_fb_putchar(uint8_t);
+extern void boot_vga_init(int);
+
+extern void vga_setpos(int, int);
+extern void vga_getpos(int *, int *);
+extern void vga_scroll(int);
+extern void vga_drawc(int, int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _BOOT_CONSOLE_IMPL_H */
diff --git a/usr/src/uts/i86pc/boot/boot_fb.c b/usr/src/uts/i86pc/boot/boot_fb.c
new file mode 100644
index 0000000000..5db2e0dcac
--- /dev/null
+++ b/usr/src/uts/i86pc/boot/boot_fb.c
@@ -0,0 +1,700 @@
+/*
+ * 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>
+ */
+
+/*
+ * dboot and early kernel needs simple putchar(int) interface to implement
+ * printf() support. So we implement simple interface on top of
+ * linear frame buffer, since we can not use tem directly, we are
+ * just borrowing bits from it.
+ *
+ * Note, this implementation is assuming UEFI linear frame buffer and
+ * 32-bit depth, which should not be issue as GOP is supposed to provide those.
+ * At the time of writing, this is the only case for frame buffer anyhow.
+ */
+
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/multiboot2.h>
+#include <sys/framebuffer.h>
+#include <sys/bootinfo.h>
+#include <sys/boot_console.h>
+#include <sys/bootconf.h>
+
+#define P2ROUNDUP(x, align) (-(-(x) & -(align)))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+/*
+ * Simplified visual_io data structures from visual_io.h
+ */
+
+struct vis_consdisplay {
+ uint16_t row; /* Row to display data at */
+ uint16_t col; /* Col to display data at */
+ uint16_t width; /* Width of data */
+ uint16_t height; /* Height of data */
+ uint8_t *data; /* Data to display */
+};
+
+struct vis_conscopy {
+ uint16_t s_row; /* Starting row */
+ uint16_t s_col; /* Starting col */
+ uint16_t e_row; /* Ending row */
+ uint16_t e_col; /* Ending col */
+ uint16_t t_row; /* Row to move to */
+ uint16_t t_col; /* Col to move to */
+};
+
+/* we have built in fonts 12x22, 6x10, 7x14 and depth 32. */
+#define MAX_GLYPH (12 * 22 * 4)
+
+static struct font boot_fb_font; /* set by set_font() */
+static uint8_t glyph[MAX_GLYPH];
+static uint32_t last_line_size;
+static fb_info_pixel_coord_t last_line;
+
+/* color translation */
+typedef struct {
+ uint8_t red[16];
+ uint8_t green[16];
+ uint8_t blue[16];
+} text_cmap_t;
+
+/* BEGIN CSTYLED */
+/* Bk Rd Gr Br Bl Mg Cy Wh */
+static uint8_t dim_xlate[] = { 1, 5, 3, 7, 2, 6, 4, 8 };
+static uint8_t brt_xlate[] = { 9, 13, 11, 15, 10, 14, 12, 0 };
+/* END CSTYLED */
+
+static text_cmap_t cmap4_to_24 = {
+/* BEGIN CSTYLED */
+/* 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 */
+ 0xff,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x40,0x00,0x00,0x00,0xff,0xff,0xff,
+ 0xff,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x80,0x40,0x00,0xff,0xff,0x00,0x00,0xff,
+ 0xff,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x40,0xff,0x00,0xff,0x00,0xff,0x00
+/* END CSTYLED */
+};
+
+/*
+ * extract data from MB2 framebuffer tag and set up initial frame buffer.
+ */
+boolean_t
+xbi_fb_init(struct xboot_info *xbi)
+{
+ multiboot_tag_framebuffer_t *tag;
+ boot_framebuffer_t *xbi_fb;
+
+ xbi_fb = (boot_framebuffer_t *)(uintptr_t)xbi->bi_framebuffer;
+ if (xbi_fb == NULL)
+ return (B_FALSE);
+
+#if !defined(_BOOT)
+ /* For early kernel, we get cursor position from dboot. */
+ fb_info.cursor.origin.x = xbi_fb->cursor.origin.x;
+ fb_info.cursor.origin.y = xbi_fb->cursor.origin.y;
+ fb_info.cursor.pos.x = xbi_fb->cursor.pos.x;
+ fb_info.cursor.pos.y = xbi_fb->cursor.pos.y;
+ fb_info.cursor.visible = xbi_fb->cursor.visible;
+#endif
+
+ tag = (multiboot_tag_framebuffer_t *)(uintptr_t)xbi_fb->framebuffer;
+ if (tag == NULL) {
+ return (B_FALSE);
+ }
+
+ fb_info.paddr = tag->framebuffer_common.framebuffer_addr;
+ fb_info.pitch = tag->framebuffer_common.framebuffer_pitch;
+ fb_info.depth = tag->framebuffer_common.framebuffer_bpp;
+ fb_info.bpp = P2ROUNDUP(fb_info.depth, 8) >> 3;
+ fb_info.screen.x = tag->framebuffer_common.framebuffer_width;
+ fb_info.screen.y = tag->framebuffer_common.framebuffer_height;
+ fb_info.fb_size = fb_info.screen.y * fb_info.pitch;
+
+ if (fb_info.paddr == 0)
+ fb_info.fb_type = FB_TYPE_UNKNOWN;
+
+ switch (tag->framebuffer_common.framebuffer_type) {
+ case MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT:
+ fb_info.fb_type = FB_TYPE_EGA_TEXT;
+ return (B_FALSE);
+
+ case MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED:
+ if (fb_info.paddr != 0)
+ fb_info.fb_type = FB_TYPE_INDEXED;
+ return (B_TRUE);
+
+ case MULTIBOOT_FRAMEBUFFER_TYPE_RGB:
+ if (fb_info.paddr != 0)
+ fb_info.fb_type = FB_TYPE_RGB;
+ break;
+
+ default:
+ return (B_FALSE);
+ }
+
+ fb_info.rgb.red.size = tag->u.fb2.framebuffer_red_mask_size;
+ fb_info.rgb.red.pos = tag->u.fb2.framebuffer_red_field_position;
+ fb_info.rgb.green.size = tag->u.fb2.framebuffer_green_mask_size;
+ fb_info.rgb.green.pos = tag->u.fb2.framebuffer_green_field_position;
+ fb_info.rgb.blue.size = tag->u.fb2.framebuffer_blue_mask_size;
+ fb_info.rgb.blue.pos = tag->u.fb2.framebuffer_blue_field_position;
+
+ return (B_TRUE);
+}
+
+/* set font and pass the data to fb_info */
+static void
+boot_fb_set_font(uint16_t height, uint16_t width)
+{
+ short h, w;
+
+ h = MIN(height, 4096);
+ w = MIN(width, 4096);
+
+ set_font(&boot_fb_font, (short *)&fb_info.terminal.y,
+ (short *)&fb_info.terminal.x, h, w);
+ fb_info.font_width = boot_fb_font.width;
+ fb_info.font_height = boot_fb_font.height;
+}
+
+/* fill framebuffer */
+static void
+boot_fb_fill(uint8_t *dst, uint32_t data, uint32_t len)
+{
+ uint16_t *dst16;
+ uint32_t *dst32;
+ uint32_t i;
+
+ switch (fb_info.depth) {
+ case 24:
+ case 8:
+ for (i = 0; i < len; i++)
+ dst[i] = (uint8_t)data;
+ break;
+ case 15:
+ case 16:
+ dst16 = (uint16_t *)dst;
+ len /= 2;
+ for (i = 0; i < len; i++) {
+ dst16[i] = (uint16_t)data;
+ }
+ break;
+ case 32:
+ dst32 = (uint32_t *)dst;
+ len /= 4;
+ for (i = 0; i < len; i++) {
+ dst32[i] = data;
+ }
+ break;
+ }
+}
+
+/* copy data to framebuffer */
+static void
+boot_fb_cpy(uint8_t *dst, uint8_t *src, uint32_t len)
+{
+ uint16_t *dst16, *src16;
+ uint32_t *dst32, *src32;
+ uint32_t i;
+
+ switch (fb_info.depth) {
+ case 24:
+ case 8:
+ for (i = 0; i < len; i++)
+ dst[i] = src[i];
+ break;
+ case 15:
+ case 16:
+ dst16 = (uint16_t *)dst;
+ src16 = (uint16_t *)src;
+ for (i = 0; i < len >> 1; i++) {
+ dst16[i] = src16[i];
+ }
+ break;
+ case 32:
+ dst32 = (uint32_t *)dst;
+ src32 = (uint32_t *)src;
+ for (i = 0; i < len >> 2; i++) {
+ dst32[i] = src32[i];
+ }
+ break;
+ }
+}
+
+/*
+ * Allocate shadow frame buffer, called from fakebop.c when early boot
+ * allocator is ready.
+ */
+void
+boot_fb_shadow_init(bootops_t *bops)
+{
+ if (boot_console_type(NULL) != CONS_FRAMEBUFFER)
+ return; /* nothing to do */
+
+ fb_info.shadow_fb = (uint8_t *)bops->bsys_alloc(NULL, NULL,
+ fb_info.fb_size, MMU_PAGESIZE);
+
+ if (fb_info.shadow_fb == NULL)
+ return;
+
+ /* Copy FB to shadow */
+ boot_fb_cpy(fb_info.shadow_fb, fb_info.fb, fb_info.fb_size);
+}
+
+/*
+ * Translate ansi color based on inverses and brightness.
+ */
+static void
+boot_get_color(uint32_t *fg, uint32_t *bg)
+{
+ /* ansi to solaris colors, see also boot_console.c */
+ if (fb_info.inverse == B_TRUE ||
+ fb_info.inverse_screen == B_TRUE) {
+ *bg = dim_xlate[fb_info.fg_color];
+ *fg = brt_xlate[fb_info.bg_color];
+ } else {
+ if (fb_info.bg_color == 7)
+ *bg = brt_xlate[fb_info.bg_color];
+ else
+ *bg = dim_xlate[fb_info.bg_color];
+ *fg = dim_xlate[fb_info.fg_color];
+ }
+}
+
+/*
+ * Map indexed color to RGB value.
+ */
+static uint32_t
+boot_color_map(uint8_t index)
+{
+ uint8_t c;
+ int pos, size;
+ uint32_t color;
+
+ /* 8bit depth is for indexed colors */
+ if (fb_info.depth == 8)
+ return (index);
+
+ if (index >= sizeof (cmap4_to_24.red))
+ index = 0;
+
+ c = cmap4_to_24.red[index];
+ pos = fb_info.rgb.red.pos;
+ size = fb_info.rgb.red.size;
+ color = ((c >> 8 - size) & ((1 << size) - 1)) << pos;
+
+ c = cmap4_to_24.green[index];
+ pos = fb_info.rgb.green.pos;
+ size = fb_info.rgb.green.size;
+ color |= ((c >> 8 - size) & ((1 << size) - 1)) << pos;
+
+ c = cmap4_to_24.blue[index];
+ pos = fb_info.rgb.blue.pos;
+ size = fb_info.rgb.blue.size;
+ color |= ((c >> 8 - size) & ((1 << size) - 1)) << pos;
+
+ return (color);
+}
+
+/* set up out simple console. */
+/*ARGSUSED*/
+void
+boot_fb_init(int console)
+{
+ fb_info_pixel_coord_t window;
+
+ /* frame buffer address is mapped in dboot. */
+ fb_info.fb = (uint8_t *)(uintptr_t)fb_info.paddr;
+
+ boot_fb_set_font(fb_info.screen.y, fb_info.screen.x);
+ window.x =
+ (fb_info.screen.x - fb_info.terminal.x * boot_fb_font.width) / 2;
+ window.y =
+ (fb_info.screen.y - fb_info.terminal.y * boot_fb_font.height) / 2;
+ fb_info.terminal_origin.x = window.x;
+ fb_info.terminal_origin.y = window.y;
+
+#if defined(_BOOT)
+ /*
+ * Being called from dboot, we can have cursor terminal
+ * position passed from boot loader. In such case, fix the
+ * cursor screen coords.
+ */
+ if (fb_info.cursor.pos.x != 0 || fb_info.cursor.pos.y != 0) {
+ fb_info.cursor.origin.x = window.x +
+ fb_info.cursor.pos.x * boot_fb_font.width;
+ fb_info.cursor.origin.y = window.y +
+ fb_info.cursor.pos.y * boot_fb_font.height;
+ }
+#endif
+
+ /* If the cursor terminal position is 0,0 just reset screen coords */
+ if (fb_info.cursor.pos.x == 0 && fb_info.cursor.pos.y == 0) {
+ fb_info.cursor.origin.x = window.x;
+ fb_info.cursor.origin.y = window.y;
+ }
+
+ /*
+ * Validate cursor coords with screen/terminal dimensions,
+ * if anything is off, reset to 0,0
+ */
+ if (fb_info.cursor.pos.x > fb_info.terminal.x ||
+ fb_info.cursor.pos.y > fb_info.terminal.y ||
+ fb_info.cursor.origin.x > fb_info.screen.x ||
+ fb_info.cursor.origin.y > fb_info.screen.y) {
+
+ fb_info.cursor.origin.x = window.x;
+ fb_info.cursor.origin.y = window.y;
+ fb_info.cursor.pos.x = 0;
+ fb_info.cursor.pos.y = 0;
+ }
+
+#if defined(_BOOT)
+ /* clear the screen if cursor is set to 0,0 */
+ fb_info.cursor.pos.x = fb_info.cursor.pos.y = 0;
+ if (console == CONS_FRAMEBUFFER &&
+ fb_info.cursor.pos.x == 0 && fb_info.cursor.pos.y == 0) {
+ uint32_t fg, bg;
+ int i;
+
+ boot_get_color(&fg, &bg);
+ bg = boot_color_map(bg);
+
+ for (i = 0; i < fb_info.screen.y; i++) {
+ uint8_t *dest = fb_info.fb + i * fb_info.pitch;
+ boot_fb_fill(dest, bg, fb_info.pitch);
+ }
+ }
+#endif
+ /* set up pre-calculated last line */
+ last_line_size = fb_info.terminal.x * boot_fb_font.width *
+ fb_info.bpp;
+ last_line.x = window.x;
+ last_line.y = window.y + (fb_info.terminal.y - 1) * boot_fb_font.height;
+
+}
+
+/* copy rectangle to framebuffer. */
+static void
+boot_fb_blit(struct vis_consdisplay *rect)
+{
+ uint32_t size; /* write size per scanline */
+ uint8_t *fbp, *sfbp; /* fb + calculated offset */
+ int i;
+
+ /* make sure we will not write past FB */
+ if (rect->col >= fb_info.screen.x ||
+ rect->row >= fb_info.screen.y ||
+ rect->col + rect->width >= fb_info.screen.x ||
+ rect->row + rect->height >= fb_info.screen.y)
+ return;
+
+ size = rect->width * fb_info.bpp;
+ fbp = fb_info.fb + rect->col * fb_info.bpp +
+ rect->row * fb_info.pitch;
+ if (fb_info.shadow_fb != NULL) {
+ sfbp = fb_info.shadow_fb + rect->col * fb_info.bpp +
+ rect->row * fb_info.pitch;
+ } else {
+ sfbp = NULL;
+ }
+
+ /* write all scanlines in rectangle */
+ for (i = 0; i < rect->height; i++) {
+ uint8_t *dest = fbp + i * fb_info.pitch;
+ uint8_t *src = rect->data + i * size;
+ boot_fb_cpy(dest, src, size);
+ if (sfbp != NULL) {
+ dest = sfbp + i * fb_info.pitch;
+ boot_fb_cpy(dest, src, size);
+ }
+ }
+}
+
+static void
+bit_to_pix(uchar_t c)
+{
+ uint32_t fg, bg;
+
+ boot_get_color(&fg, &bg);
+ fg = boot_color_map(fg);
+ bg = boot_color_map(bg);
+
+ switch (fb_info.depth) {
+ case 8:
+ font_bit_to_pix8(&boot_fb_font, (uint8_t *)glyph, c, fg, bg);
+ break;
+ case 15:
+ case 16:
+ font_bit_to_pix16(&boot_fb_font, (uint16_t *)glyph, c,
+ (uint16_t)fg, (uint16_t)bg);
+ break;
+ case 24:
+ font_bit_to_pix24(&boot_fb_font, (uint8_t *)glyph, c, fg, bg);
+ break;
+ case 32:
+ font_bit_to_pix32(&boot_fb_font, (uint32_t *)glyph, c, fg, bg);
+ break;
+ }
+}
+
+/*
+ * move the terminal window lines [1..y] to [0..y-1] and clear last line.
+ */
+static void
+boot_fb_scroll(void)
+{
+ struct vis_conscopy c_copy;
+ uint32_t soffset, toffset;
+ uint32_t width, height;
+ uint32_t fg, bg;
+ uint8_t *src, *dst, *sdst;
+ int i;
+
+ boot_get_color(&fg, &bg);
+ bg = boot_color_map(bg);
+
+ /* support for scrolling. set up the console copy data and last line */
+ c_copy.s_row = fb_info.terminal_origin.y + boot_fb_font.height;
+ c_copy.s_col = fb_info.terminal_origin.x;
+ c_copy.e_row = fb_info.screen.y - fb_info.terminal_origin.y;
+ c_copy.e_col = fb_info.screen.x - fb_info.terminal_origin.x;
+ c_copy.t_row = fb_info.terminal_origin.y;
+ c_copy.t_col = fb_info.terminal_origin.x;
+
+ soffset = c_copy.s_col * fb_info.bpp + c_copy.s_row * fb_info.pitch;
+ toffset = c_copy.t_col * fb_info.bpp + c_copy.t_row * fb_info.pitch;
+ if (fb_info.shadow_fb != NULL) {
+ src = fb_info.shadow_fb + soffset;
+ sdst = fb_info.shadow_fb + toffset;
+ } else {
+ src = fb_info.fb + soffset;
+ sdst = NULL;
+ }
+ dst = fb_info.fb + toffset;
+
+ width = (c_copy.e_col - c_copy.s_col + 1) * fb_info.bpp;
+ height = c_copy.e_row - c_copy.s_row + 1;
+ for (i = 0; i < height; i++) {
+ uint32_t increment = i * fb_info.pitch;
+ boot_fb_cpy(dst + increment, src + increment, width);
+ if (sdst != NULL)
+ boot_fb_cpy(sdst + increment, src + increment, width);
+ }
+
+ /* now clean up the last line */
+ toffset = last_line.x * fb_info.bpp + last_line.y * fb_info.pitch;
+ dst = fb_info.fb + toffset;
+ if (fb_info.shadow_fb != NULL)
+ sdst = fb_info.shadow_fb + toffset;
+
+ for (i = 0; i < boot_fb_font.height; i++) {
+ uint8_t *dest = dst + i * fb_info.pitch;
+ if (fb_info.fb + fb_info.fb_size >= dest + last_line_size)
+ boot_fb_fill(dest, bg, last_line_size);
+ if (sdst != NULL) {
+ dest = sdst + i * fb_info.pitch;
+ if (fb_info.shadow_fb + fb_info.fb_size >=
+ dest + last_line_size) {
+ boot_fb_fill(dest, bg, last_line_size);
+ }
+ }
+ }
+}
+
+/*
+ * Very simple block cursor. Save space below the cursor and restore
+ * when cursor is invisible.
+ */
+void
+boot_fb_cursor(boolean_t visible)
+{
+ uint32_t offset, size;
+ uint32_t *fb32, *sfb32 = NULL;
+ uint32_t fg, bg;
+ uint16_t *fb16, *sfb16 = NULL;
+ uint8_t *fb8, *sfb8 = NULL;
+ int i, pitch;
+
+ if (fb_info.cursor.visible == visible)
+ return;
+
+ boot_get_color(&fg, &bg);
+ fg = boot_color_map(fg);
+ bg = boot_color_map(bg);
+
+ fb_info.cursor.visible = visible;
+ pitch = fb_info.pitch;
+ size = boot_fb_font.width * fb_info.bpp;
+
+ /*
+ * Build cursor image. We are building mirror image of data on
+ * frame buffer by (D xor FG) xor BG.
+ */
+ offset = fb_info.cursor.origin.x * fb_info.bpp +
+ fb_info.cursor.origin.y * pitch;
+ switch (fb_info.depth) {
+ case 8:
+ for (i = 0; i < boot_fb_font.height; i++) {
+ fb8 = fb_info.fb + offset + i * pitch;
+ if (fb_info.shadow_fb != NULL)
+ sfb8 = fb_info.shadow_fb + offset + i * pitch;
+ for (uint32_t j = 0; j < size; j += 1) {
+ fb8[j] = (fb8[j] ^ (fg & 0xff)) ^ (bg & 0xff);
+
+ if (sfb8 == NULL)
+ continue;
+
+ sfb8[j] = (sfb8[j] ^ (fg & 0xff)) ^ (bg & 0xff);
+ }
+ }
+ break;
+ case 15:
+ case 16:
+ for (i = 0; i < boot_fb_font.height; i++) {
+ fb16 = (uint16_t *)(fb_info.fb + offset + i * pitch);
+ if (fb_info.shadow_fb != NULL)
+ sfb16 = (uint16_t *)
+ (fb_info.shadow_fb + offset + i * pitch);
+ for (int j = 0; j < boot_fb_font.width; j++) {
+ fb16[j] = (fb16[j] ^ (fg & 0xffff)) ^
+ (bg & 0xffff);
+
+ if (sfb16 == NULL)
+ continue;
+
+ sfb16[j] = (sfb16[j] ^ (fg & 0xffff)) ^
+ (bg & 0xffff);
+ }
+ }
+ break;
+ case 24:
+ for (i = 0; i < boot_fb_font.height; i++) {
+ fb8 = fb_info.fb + offset + i * pitch;
+ if (fb_info.shadow_fb != NULL)
+ sfb8 = fb_info.shadow_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);
+
+ if (sfb8 == NULL)
+ continue;
+
+ sfb8[j] = (sfb8[j] ^ ((fg >> 16) & 0xff)) ^
+ ((bg >> 16) & 0xff);
+ sfb8[j+1] = (sfb8[j+1] ^ ((fg >> 8) & 0xff)) ^
+ ((bg >> 8) & 0xff);
+ sfb8[j+2] = (sfb8[j+2] ^ (fg & 0xff)) ^
+ (bg & 0xff);
+ }
+ }
+ break;
+ case 32:
+ for (i = 0; i < boot_fb_font.height; i++) {
+ fb32 = (uint32_t *)(fb_info.fb + offset + i * pitch);
+ if (fb_info.shadow_fb != NULL) {
+ sfb32 = (uint32_t *)
+ (fb_info.shadow_fb + offset + i * pitch);
+ }
+ for (int j = 0; j < boot_fb_font.width; j++) {
+ fb32[j] = (fb32[j] ^ fg) ^ bg;
+
+ if (sfb32 == NULL)
+ continue;
+
+ sfb32[j] = (sfb32[j] ^ fg) ^ bg;
+ }
+ }
+ break;
+ }
+}
+
+static void
+set_cursor_row(void)
+{
+ fb_info.cursor.pos.y++;
+ fb_info.cursor.pos.x = 0;
+ fb_info.cursor.origin.x = fb_info.terminal_origin.x;
+
+ if (fb_info.cursor.pos.y < fb_info.terminal.y &&
+ fb_info.cursor.origin.y + boot_fb_font.height < fb_info.screen.y) {
+ fb_info.cursor.origin.y += boot_fb_font.height;
+ } else {
+ fb_info.cursor.pos.y = fb_info.terminal.y - 1;
+ /* fix the cursor origin y */
+ fb_info.cursor.origin.y = fb_info.terminal_origin.y +
+ boot_fb_font.height * fb_info.cursor.pos.y;
+ boot_fb_scroll();
+ }
+}
+
+static void
+set_cursor_col(void)
+{
+ fb_info.cursor.pos.x++;
+ if (fb_info.cursor.pos.x < fb_info.terminal.x &&
+ fb_info.cursor.origin.x + boot_fb_font.width < fb_info.screen.x) {
+ fb_info.cursor.origin.x += boot_fb_font.width;
+ } else {
+ fb_info.cursor.pos.x = 0;
+ fb_info.cursor.origin.x = fb_info.terminal_origin.x;
+ set_cursor_row();
+ }
+}
+
+void
+boot_fb_putchar(uint8_t c)
+{
+ struct vis_consdisplay display;
+ boolean_t bs = B_FALSE;
+
+ /* early tem startup will switch cursor off, if so, keep it off */
+ boot_fb_cursor(B_FALSE); /* cursor off */
+ switch (c) {
+ case '\n':
+ set_cursor_row();
+ boot_fb_cursor(B_TRUE);
+ return;
+ case '\r':
+ fb_info.cursor.pos.x = 0;
+ fb_info.cursor.origin.x = fb_info.terminal_origin.x;
+ boot_fb_cursor(B_TRUE);
+ return;
+ case '\b':
+ if (fb_info.cursor.pos.x > 0) {
+ fb_info.cursor.pos.x--;
+ fb_info.cursor.origin.x -= boot_fb_font.width;
+ }
+ c = ' ';
+ bs = B_TRUE;
+ break;
+ }
+
+ bit_to_pix(c);
+ display.col = fb_info.cursor.origin.x;
+ display.row = fb_info.cursor.origin.y;
+ display.width = boot_fb_font.width;
+ display.height = boot_fb_font.height;
+ display.data = glyph;
+
+ boot_fb_blit(&display);
+ if (bs == B_FALSE)
+ set_cursor_col();
+ boot_fb_cursor(B_TRUE);
+}
diff --git a/usr/src/uts/i86pc/boot/boot_vga.c b/usr/src/uts/i86pc/boot/boot_vga.c
index 45c17a340f..3526964662 100644
--- a/usr/src/uts/i86pc/boot/boot_vga.c
+++ b/usr/src/uts/i86pc/boot/boot_vga.c
@@ -24,25 +24,20 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Miniature VGA driver for bootstrap.
*/
#include <sys/archsystm.h>
#include <sys/vgareg.h>
+#include <sys/framebuffer.h>
-#include "boot_vga.h"
-
+#include "boot_console_impl.h"
#if defined(_BOOT)
#include "../dboot/dboot_asm.h"
#include "../dboot/dboot_xboot.h"
#endif
-#define VGA_COLOR_CRTC_INDEX 0x3d4
-#define VGA_COLOR_CRTC_DATA 0x3d5
-
#if defined(__xpv) && defined(_BOOT)
/*
@@ -60,15 +55,63 @@ extern unsigned short *video_fb;
#else /* __xpv && _BOOT */
/* Device memory address */
-#define VGA_SCREEN ((unsigned short *)0xb8000)
+#define VGA_SCREEN ((uint16_t *)(VGA_MEM_ADDR + VGA_COLOR_BASE))
#endif /* __xpv && _BOOT */
+static void vga_init(void);
+static void vga_cursor_display(void);
+static void vga_clear(int);
static void vga_set_crtc(int index, unsigned char val);
static unsigned char vga_get_crtc(int index);
+static void vga_set_atr(int index, unsigned char val);
+static unsigned char vga_get_atr(int index);
void
+boot_vga_init(int cons_color)
+{
+ fb_info.terminal.x = VGA_TEXT_COLS;
+ fb_info.terminal.y = VGA_TEXT_ROWS;
+
+#if defined(_BOOT)
+ /*
+ * Note that we have to enable the cursor before clearing the
+ * screen since the cursor position is dependant upon the cursor
+ * skew, which is initialized by vga_cursor_display()
+ */
+ vga_init();
+ fb_info.cursor.visible = B_FALSE;
+ vga_cursor_display();
+
+ /*
+ * In general we should avoid resetting the display during the boot,
+ * we may have valueable messages there, this why the "native" loader
+ * boot does pass the console state down to kernel and we do try to
+ * pick the state. However, the loader is not the only way to boot.
+ * The non-native boot loaders do not implement the smooth console.
+ * If we have no information about cursor location, we will get value
+ * (0, 0) and that means we better clear the screen.
+ */
+ if (fb_info.cursor.pos.x == 0 && fb_info.cursor.pos.y == 0)
+ vga_clear(cons_color);
+ vga_setpos(fb_info.cursor.pos.y, fb_info.cursor.pos.x);
+#endif /* _BOOT */
+}
+
+static void
+vga_init(void)
+{
+ unsigned char val;
+
+ /* set 16bit colors */
+ val = vga_get_atr(VGA_ATR_MODE);
+ val &= ~VGA_ATR_MODE_BLINK;
+ val &= ~VGA_ATR_MODE_9WIDE;
+ vga_set_atr(VGA_ATR_MODE, val);
+}
+
+static void
vga_cursor_display(void)
{
unsigned char val, msl;
@@ -88,8 +131,8 @@ vga_cursor_display(void)
* line value.
* - Bit 5 is the cursor disable bit.
*/
- val = vga_get_crtc(VGA_CRTC_CSSL);
- vga_set_crtc(VGA_CRTC_CSSL, (val & 0xc) | ((msl - 2) & 0x1f));
+ val = vga_get_crtc(VGA_CRTC_CSSL) & 0xc0;
+ vga_set_crtc(VGA_CRTC_CSSL, val);
/*
* Continue setting the cursors size.
@@ -103,7 +146,7 @@ vga_cursor_display(void)
}
-void
+static void
vga_clear(int color)
{
unsigned short val;
@@ -150,6 +193,9 @@ vga_setpos(int row, int col)
off = row * VGA_TEXT_COLS + col;
vga_set_crtc(VGA_CRTC_CLAH, off >> 8);
vga_set_crtc(VGA_CRTC_CLAL, off & 0xff);
+
+ fb_info.cursor.pos.y = row;
+ fb_info.cursor.pos.x = col;
}
void
@@ -163,15 +209,41 @@ vga_getpos(int *row, int *col)
}
static void
+vga_set_atr(int index, unsigned char val)
+{
+ (void) inb(VGA_REG_ADDR + CGA_STAT);
+ outb(VGA_REG_ADDR + VGA_ATR_AD, index);
+ outb(VGA_REG_ADDR + VGA_ATR_AD, val);
+
+ (void) inb(VGA_REG_ADDR + CGA_STAT);
+ outb(VGA_REG_ADDR + VGA_ATR_AD, VGA_ATR_ENB_PLT);
+}
+
+static unsigned char
+vga_get_atr(int index)
+{
+ unsigned char val;
+
+ (void) inb(VGA_REG_ADDR + CGA_STAT);
+ outb(VGA_REG_ADDR + VGA_ATR_AD, index);
+ val = inb(VGA_REG_ADDR + VGA_ATR_DATA);
+
+ (void) inb(VGA_REG_ADDR + CGA_STAT);
+ outb(VGA_REG_ADDR + VGA_ATR_AD, VGA_ATR_ENB_PLT);
+
+ return (val);
+}
+
+static void
vga_set_crtc(int index, unsigned char val)
{
- outb(VGA_COLOR_CRTC_INDEX, index);
- outb(VGA_COLOR_CRTC_DATA, val);
+ outb(VGA_REG_ADDR + VGA_CRTC_ADR, index);
+ outb(VGA_REG_ADDR + VGA_CRTC_DATA, val);
}
static unsigned char
vga_get_crtc(int index)
{
- outb(VGA_COLOR_CRTC_INDEX, index);
- return (inb(VGA_COLOR_CRTC_DATA));
+ outb(VGA_REG_ADDR + VGA_CRTC_ADR, index);
+ return (inb(VGA_REG_ADDR + VGA_CRTC_DATA));
}
diff --git a/usr/src/uts/i86pc/boot/boot_vga.h b/usr/src/uts/i86pc/boot/boot_vga.h
deleted file mode 100644
index d4f11cbe4b..0000000000
--- a/usr/src/uts/i86pc/boot/boot_vga.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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 2007 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#ifndef _BOOT_VGA_H
-#define _BOOT_VGA_H
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-/*
- * Interface to the bootstrap's internal VGA driver.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define VGA_IO_WMR 0x3C8 /* vga io DAC write mode register */
-#define VGA_IO_DR 0x3C9 /* vga io DAC data register */
-#define VGA_IO_IS 0x3DA /* vga io input status register */
-
-#define VGA_TEXT_COLS 80
-#define VGA_TEXT_ROWS 25
-
-extern void vga_setpos(int, int);
-extern void vga_getpos(int *, int *);
-extern void vga_clear(int);
-extern void vga_scroll(int);
-extern void vga_drawc(int, int);
-extern void vga_cursor_display(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _BOOT_VGA_H */
diff --git a/usr/src/uts/i86pc/dboot/dboot_startkern.c b/usr/src/uts/i86pc/dboot/dboot_startkern.c
index fc045f9164..4e18f2b9a8 100644
--- a/usr/src/uts/i86pc/dboot/dboot_startkern.c
+++ b/usr/src/uts/i86pc/dboot/dboot_startkern.c
@@ -36,6 +36,7 @@
#include <sys/multiboot2.h>
#include <sys/multiboot2_impl.h>
#include <sys/sysmacros.h>
+#include <sys/framebuffer.h>
#include <sys/sha1.h>
#include <util/string.h>
#include <util/strtolctype.h>
@@ -153,6 +154,8 @@ multiboot_tag_mmap_t *mb2_mmap_tagp;
int num_entries; /* mmap entry count */
boolean_t num_entries_set; /* is mmap entry count set */
uintptr_t load_addr;
+static boot_framebuffer_t framebuffer __aligned(16);
+static boot_framebuffer_t *fb;
/* can not be automatic variables because of alignment */
static efi_guid_t smbios3 = SMBIOS3_TABLE_GUID;
@@ -164,7 +167,7 @@ static efi_guid_t acpi1 = ACPI_10_TABLE_GUID;
/*
* This contains information passed to the kernel
*/
-struct xboot_info boot_info[2]; /* extra space to fix alignement for amd64 */
+struct xboot_info boot_info __aligned(16);
struct xboot_info *bi;
/*
@@ -180,6 +183,7 @@ int largepage_support = 0;
int pae_support = 0;
int pge_support = 0;
int NX_support = 0;
+int PAT_support = 0;
/*
* Low 32 bits of kernel entry address passed back to assembler.
@@ -989,16 +993,16 @@ init_mem_alloc(void)
static void
dboot_multiboot1_xboot_consinfo(void)
{
- bi->bi_framebuffer = NULL;
+ fb->framebuffer = 0;
}
static void
dboot_multiboot2_xboot_consinfo(void)
{
- multiboot_tag_framebuffer_t *fb;
- fb = dboot_multiboot2_find_tag(mb2_info,
+ multiboot_tag_framebuffer_t *fbtag;
+ fbtag = dboot_multiboot2_find_tag(mb2_info,
MULTIBOOT_TAG_TYPE_FRAMEBUFFER);
- bi->bi_framebuffer = (native_ptr_t)(uintptr_t)fb;
+ fb->framebuffer = (uint64_t)(uintptr_t)fbtag;
}
static int
@@ -2070,24 +2074,29 @@ build_page_tables(void)
* Map framebuffer memory as PT_NOCACHE as this is memory from a
* device and therefore must not be cached.
*/
- if (bi->bi_framebuffer != NULL) {
- multiboot_tag_framebuffer_t *fb;
- fb = (multiboot_tag_framebuffer_t *)(uintptr_t)
- bi->bi_framebuffer;
+ if (bi->bi_framebuffer != NULL && fb->framebuffer != 0) {
+ multiboot_tag_framebuffer_t *fb_tagp;
+ fb_tagp = (multiboot_tag_framebuffer_t *)(uintptr_t)
+ fb->framebuffer;
- start = fb->framebuffer_common.framebuffer_addr;
- end = start + fb->framebuffer_common.framebuffer_height *
- fb->framebuffer_common.framebuffer_pitch;
+ start = fb_tagp->framebuffer_common.framebuffer_addr;
+ end = start + fb_tagp->framebuffer_common.framebuffer_height *
+ fb_tagp->framebuffer_common.framebuffer_pitch;
if (map_debug)
dboot_printf("FB 1:1 map pa=%" PRIx64 "..%" PRIx64 "\n",
start, end);
pte_bits |= PT_NOCACHE;
+ if (PAT_support != 0)
+ pte_bits |= PT_PAT_4K;
+
while (start < end) {
map_pa_at_va(start, start, 0);
start += MMU_PAGESIZE;
}
pte_bits &= ~PT_NOCACHE;
+ if (PAT_support != 0)
+ pte_bits &= ~PT_PAT_4K;
}
#endif /* !__xpv */
@@ -2104,15 +2113,12 @@ See http://illumos.org/msg/SUNOS-8000-AK for details.\n"
static void
dboot_init_xboot_consinfo(void)
{
- uintptr_t addr;
- /*
- * boot info must be 16 byte aligned for 64 bit kernel ABI
- */
- addr = (uintptr_t)boot_info;
- addr = (addr + 0xf) & ~0xf;
- bi = (struct xboot_info *)addr;
+ bi = &boot_info;
#if !defined(__xpv)
+ fb = &framebuffer;
+ bi->bi_framebuffer = (native_ptr_t)(uintptr_t)fb;
+
switch (multiboot_version) {
case 1:
dboot_multiboot1_xboot_consinfo();
@@ -2398,6 +2404,16 @@ startup_kernel(void)
}
}
+ /*
+ * check for PAT support
+ */
+ {
+ uint32_t eax = 1;
+ uint32_t edx = get_cpuid_edx(&eax);
+
+ if (edx & CPUID_INTC_EDX_PAT)
+ PAT_support = 1;
+ }
#if !defined(_BOOT_TARGET_amd64)
/*
@@ -2439,6 +2455,8 @@ startup_kernel(void)
pge_support = 1;
if (edx & CPUID_INTC_EDX_PAE)
pae_support = 1;
+ if (edx & CPUID_INTC_EDX_PAT)
+ PAT_support = 1;
eax = 0x80000000;
edx = get_cpuid_edx(&eax);
@@ -2508,6 +2526,7 @@ startup_kernel(void)
top_level = 1;
}
+ DBG(PAT_support);
DBG(pge_support);
DBG(NX_support);
DBG(largepage_support);
@@ -2608,4 +2627,13 @@ startup_kernel(void)
#endif
DBG_MSG("\n\n*** DBOOT DONE -- back to asm to jump to kernel\n\n");
+
+#ifndef __xpv
+ /* Update boot info with FB data */
+ fb->cursor.origin.x = fb_info.cursor.origin.x;
+ fb->cursor.origin.y = fb_info.cursor.origin.y;
+ fb->cursor.pos.x = fb_info.cursor.pos.x;
+ fb->cursor.pos.y = fb_info.cursor.pos.y;
+ fb->cursor.visible = fb_info.cursor.visible;
+#endif
}
diff --git a/usr/src/uts/i86pc/os/fakebop.c b/usr/src/uts/i86pc/os/fakebop.c
index 1544eab3b6..0fb3bb486a 100644
--- a/usr/src/uts/i86pc/os/fakebop.c
+++ b/usr/src/uts/i86pc/os/fakebop.c
@@ -50,6 +50,7 @@
#include <sys/machsystm.h>
#include <sys/archsystm.h>
#include <sys/boot_console.h>
+#include <sys/framebuffer.h>
#include <sys/cmn_err.h>
#include <sys/systm.h>
#include <sys/promif.h>
@@ -92,6 +93,9 @@ static uint_t kbm_debug = 0;
bcons_putchar(*cp); \
}
+/* callback to boot_fb to set shadow frame buffer */
+extern void boot_fb_shadow_init(bootops_t *);
+
bootops_t bootop; /* simple bootops we'll pass on to kernel */
struct bsys_mem bm;
@@ -2147,6 +2151,8 @@ _start(struct xboot_info *xbp)
*/
bop_idt_init();
#endif
+ /* Set up the shadow fb for framebuffer console */
+ boot_fb_shadow_init(bops);
/*
* Start building the boot properties from the command line
diff --git a/usr/src/uts/i86pc/sys/boot_console.h b/usr/src/uts/i86pc/sys/boot_console.h
index 187733615c..4b6a6ba251 100644
--- a/usr/src/uts/i86pc/sys/boot_console.h
+++ b/usr/src/uts/i86pc/sys/boot_console.h
@@ -45,9 +45,10 @@ extern "C" {
#define CONS_USBSER 3
#define CONS_HYPERVISOR 4
#define CONS_SCREEN_GRAPHICS 5
+#define CONS_FRAMEBUFFER 6
#define CONS_MIN CONS_SCREEN_TEXT
-#define CONS_MAX CONS_SCREEN_GRAPHICS
+#define CONS_MAX CONS_FRAMEBUFFER
#define CONS_COLOR 7
diff --git a/usr/src/uts/i86pc/sys/framebuffer.h b/usr/src/uts/i86pc/sys/framebuffer.h
new file mode 100644
index 0000000000..7df7920873
--- /dev/null
+++ b/usr/src/uts/i86pc/sys/framebuffer.h
@@ -0,0 +1,91 @@
+/*
+ * 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>
+ */
+
+#ifndef _SYS_FRAMEBUFFER_H
+#define _SYS_FRAMEBUFFER_H
+
+/*
+ * Framebuffer info from boot loader. Collect linear framebuffer data
+ * provided by boot loader and early boot setup.
+ * Note the UEFI and multiboot2 present data with slight differences.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <sys/font.h>
+#include <sys/rgb.h>
+
+typedef struct fb_info_pixel_coord {
+ uint16_t x;
+ uint16_t y;
+} fb_info_pixel_coord_t;
+
+typedef struct fb_info_char_coord {
+ uint16_t x;
+ uint16_t y;
+} fb_info_char_coord_t;
+
+typedef struct fb_cursor {
+ fb_info_pixel_coord_t origin; /* cursor upper left */
+ fb_info_char_coord_t pos; /* cursor coord in chars */
+ boolean_t visible;
+} fb_cursor_t;
+
+typedef struct boot_framebuffer {
+ uint64_t framebuffer; /* native_ptr_t */
+ fb_cursor_t cursor;
+} __packed boot_framebuffer_t;
+
+typedef enum fb_type {
+ FB_TYPE_UNINITIALIZED = 0, /* FB not set up, use vga text mode */
+ FB_TYPE_EGA_TEXT, /* vga text mode */
+ FB_TYPE_INDEXED, /* FB mode */
+ FB_TYPE_RGB, /* FB mode */
+ FB_TYPE_UNKNOWN
+} fb_type_t;
+
+typedef struct fb_info {
+ fb_type_t fb_type; /* Marker from xbi_fb_init */
+ uint64_t paddr; /* FB address from bootloader */
+ uint8_t *fb; /* kernel mapped frame buffer */
+ uint8_t *shadow_fb;
+ uint64_t fb_size; /* mapped FB size in bytes */
+ uint32_t pitch; /* scan line in bytes */
+ uint8_t bpp; /* bytes per pixel */
+ uint8_t depth; /* bits per pixel */
+ uint8_t fg_color; /* ansi foreground */
+ uint8_t bg_color; /* ansi background */
+ rgb_t rgb;
+ fb_info_pixel_coord_t screen; /* screen size */
+ fb_info_pixel_coord_t terminal_origin; /* terminal upper left corner */
+ fb_info_char_coord_t terminal; /* terminal size in chars */
+ fb_cursor_t cursor;
+ uint16_t font_width;
+ uint16_t font_height;
+ boolean_t inverse;
+ boolean_t inverse_screen;
+} fb_info_t;
+
+extern fb_info_t fb_info;
+void boot_fb_cursor(boolean_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_FRAMEBUFFER_H */
diff --git a/usr/src/uts/i86pc/sys/rgb.h b/usr/src/uts/i86pc/sys/rgb.h
new file mode 100644
index 0000000000..1858e8e928
--- /dev/null
+++ b/usr/src/uts/i86pc/sys/rgb.h
@@ -0,0 +1,44 @@
+/*
+ * 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>
+ */
+
+#ifndef _SYS_RGB_H
+#define _SYS_RGB_H
+
+/*
+ * Color data from bootloader.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+
+typedef struct rgb_color {
+ uint8_t pos;
+ uint8_t size;
+} rgb_color_t;
+
+typedef struct rgb {
+ rgb_color_t red;
+ rgb_color_t green;
+ rgb_color_t blue;
+} rgb_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_RGB_H */
diff --git a/usr/src/uts/i86xpv/Makefile.files b/usr/src/uts/i86xpv/Makefile.files
index 5e1bb3cd30..d838b02290 100644
--- a/usr/src/uts/i86xpv/Makefile.files
+++ b/usr/src/uts/i86xpv/Makefile.files
@@ -120,6 +120,7 @@ BOOT_DRIVER_OBJS = \
boot_keyboard_table.o \
boot_mmu.o \
boot_vga.o \
+ boot_fb.o \
boot_xconsole.o \
dboot_multiboot2.o \
$(FONT_OBJS)