diff options
author | Jerry Jelinek <jerry.jelinek@joyent.com> | 2019-01-25 13:15:50 +0000 |
---|---|---|
committer | Jerry Jelinek <jerry.jelinek@joyent.com> | 2019-01-25 13:15:50 +0000 |
commit | 5d687f5a37b08ffb3af39f1fc475eba83078c761 (patch) | |
tree | c13f03cf095cdb500c0e65e55da28f6d234af830 | |
parent | ce6a7649078ae9f0ae246da1fffb1343093388f2 (diff) | |
parent | 8e6d016f3eedbcabf3a3bc35224bca733dc405a4 (diff) | |
download | illumos-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/packaging | 4 | ||||
-rw-r--r-- | usr/src/cmd/Makefile | 5 | ||||
-rw-r--r-- | usr/src/lib/libeti/form/common/field.c | 13 | ||||
-rw-r--r-- | usr/src/man/man5/Makefile | 3 | ||||
-rw-r--r-- | usr/src/man/man7d/Makefile | 3 | ||||
-rw-r--r-- | usr/src/pkg/manifests/diagnostic-cpu-counters.mf | 40 | ||||
-rw-r--r-- | usr/src/uts/common/sys/vgareg.h | 28 | ||||
-rw-r--r-- | usr/src/uts/i86pc/Makefile.files | 1 | ||||
-rw-r--r-- | usr/src/uts/i86pc/boot/boot_console.c | 214 | ||||
-rw-r--r-- | usr/src/uts/i86pc/boot/boot_console_impl.h | 44 | ||||
-rw-r--r-- | usr/src/uts/i86pc/boot/boot_fb.c | 700 | ||||
-rw-r--r-- | usr/src/uts/i86pc/boot/boot_vga.c | 102 | ||||
-rw-r--r-- | usr/src/uts/i86pc/boot/boot_vga.h | 57 | ||||
-rw-r--r-- | usr/src/uts/i86pc/dboot/dboot_startkern.c | 66 | ||||
-rw-r--r-- | usr/src/uts/i86pc/os/fakebop.c | 6 | ||||
-rw-r--r-- | usr/src/uts/i86pc/sys/boot_console.h | 3 | ||||
-rw-r--r-- | usr/src/uts/i86pc/sys/framebuffer.h | 91 | ||||
-rw-r--r-- | usr/src/uts/i86pc/sys/rgb.h | 44 | ||||
-rw-r--r-- | usr/src/uts/i86xpv/Makefile.files | 1 |
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) |