75ac3a7359
This feature is inspired by another Unix-alike OS commonly found on airplane headrests. A number of beasties[0] are drawn at top of framebuffer during boot, based on the number of active SMP CPUs[1]. Console buffer output continues to scroll in the screen area below beastie(s)[2]. After some time[3] has passed, the beasties are erased leaving the entire terminal for use. Includes two 80x80 vga16 beastie graphics and an 80x80 vga16 orb graphic. (The graphics are RLE compressed to save some space -- 3x 3200 bytes uncompressed, or 4208 compressed.) [0]: The user may select the style of beastie with kern.vt.splash_cpu_style=(0|1|2) [1]: Or the number may be overridden with tunable kern.vt.splash_ncpu. [2]: https://www.youtube.com/watch?v=UP2jizfr3_o [3]: Configurable with kern.vt.splash_cpu_duration (seconds, def. 10). Differential Revision: https://reviews.freebsd.org/D2181 Reviewed by: dumbbell, emaste Approved by: markj (mentor) MFC after: 2 weeks
267 lines
6.2 KiB
C
267 lines
6.2 KiB
C
/*-
|
|
* Copyright (c) 2015 Conrad Meyer <cse.cem@gmail.com>
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/callout.h>
|
|
#include <sys/cons.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/smp.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/terminal.h>
|
|
|
|
#include <dev/vt/vt.h>
|
|
|
|
extern const unsigned char vt_beastie_vga16[];
|
|
extern const unsigned char vt_beastie2_vga16[];
|
|
extern const unsigned char vt_orb_vga16[];
|
|
|
|
static struct callout vt_splash_cpu_callout;
|
|
|
|
static inline unsigned char
|
|
vt_vga2bsd(unsigned char vga)
|
|
{
|
|
static const unsigned char lut[8] = {
|
|
0,
|
|
4, /* 1 and 4 swap */
|
|
2,
|
|
6, /* 3 and 6 swap */
|
|
1, /* 4 and 1 swap */
|
|
5,
|
|
3, /* 6 and 3 swap */
|
|
7,
|
|
};
|
|
unsigned int bright;
|
|
|
|
bright = (vga & 0x8);
|
|
return (lut[vga & 0x7] | bright);
|
|
}
|
|
|
|
static void
|
|
vt_draw_2_vga16_px(struct vt_device *vd, vt_axis_t x, vt_axis_t y,
|
|
unsigned char color)
|
|
{
|
|
|
|
vd->vd_driver->vd_setpixel(vd, x, y, vt_vga2bsd(color >> 4));
|
|
vd->vd_driver->vd_setpixel(vd, x + 1, y, vt_vga2bsd(color & 0xf));
|
|
}
|
|
|
|
static void
|
|
vt_draw_1_logo(struct vt_device *vd, vt_axis_t top, vt_axis_t left)
|
|
{
|
|
const unsigned char rle_sent = 0x16, *data;
|
|
unsigned int xy, run, runcolor, i;
|
|
|
|
switch (vt_splash_cpu_style) {
|
|
case VT_LOGOS_DRAW_ALT_BEASTIE:
|
|
data = vt_beastie2_vga16;
|
|
break;
|
|
case VT_LOGOS_DRAW_ORB:
|
|
data = vt_orb_vga16;
|
|
break;
|
|
case VT_LOGOS_DRAW_BEASTIE:
|
|
/* FALLTHROUGH */
|
|
default:
|
|
data = vt_beastie_vga16;
|
|
break;
|
|
}
|
|
|
|
/* Decode basic RLE (gets us to 30-40% of uncompressed data size): */
|
|
for (i = 0, xy = 0; xy < vt_logo_sprite_height * vt_logo_sprite_width;) {
|
|
if (data[i] == rle_sent) {
|
|
runcolor = data[i + 1];
|
|
run = data[i + 2];
|
|
|
|
for (; run; run--, xy += 2)
|
|
vt_draw_2_vga16_px(vd,
|
|
left + (xy % vt_logo_sprite_width),
|
|
top + (xy / vt_logo_sprite_width),
|
|
runcolor);
|
|
|
|
i += 3;
|
|
} else {
|
|
vt_draw_2_vga16_px(vd, left + (xy % vt_logo_sprite_width),
|
|
top + (xy / vt_logo_sprite_width), data[i]);
|
|
|
|
i++;
|
|
xy += 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
vtterm_draw_cpu_logos(struct vt_device *vd)
|
|
{
|
|
unsigned int ncpu, i;
|
|
vt_axis_t left;
|
|
|
|
if (vt_splash_ncpu)
|
|
ncpu = vt_splash_ncpu;
|
|
else {
|
|
ncpu = mp_ncpus;
|
|
if (ncpu < 1)
|
|
ncpu = 1;
|
|
}
|
|
|
|
if (vd->vd_driver->vd_drawrect)
|
|
vd->vd_driver->vd_drawrect(vd, 0, 0, vd->vd_width,
|
|
vt_logo_sprite_height, 1, TC_BLACK);
|
|
/*
|
|
* Blank is okay because we only ever draw beasties on full screen
|
|
* refreshes.
|
|
*/
|
|
else if (vd->vd_driver->vd_blank)
|
|
vd->vd_driver->vd_blank(vd, TC_BLACK);
|
|
|
|
ncpu = MIN(ncpu, vd->vd_width / vt_logo_sprite_width);
|
|
for (i = 0, left = 0; i < ncpu; left += vt_logo_sprite_width, i++)
|
|
vt_draw_1_logo(vd, 0, left);
|
|
}
|
|
|
|
static void
|
|
vt_fini_logos(void *dummy __unused)
|
|
{
|
|
struct vt_device *vd;
|
|
struct vt_window *vw;
|
|
struct terminal *tm;
|
|
struct vt_font *vf;
|
|
struct winsize wsz;
|
|
term_pos_t size;
|
|
|
|
if (!vt_draw_logo_cpus)
|
|
return;
|
|
if (!vty_enabled(VTY_VT))
|
|
return;
|
|
if (!vt_splash_cpu)
|
|
return;
|
|
|
|
tm = &vt_consterm;
|
|
vw = tm->tm_softc;
|
|
if (vw == NULL)
|
|
return;
|
|
vd = vw->vw_device;
|
|
if (vd == NULL)
|
|
return;
|
|
vf = vw->vw_font;
|
|
if (vf == NULL)
|
|
return;
|
|
|
|
VT_LOCK(vd);
|
|
if ((vd->vd_flags & (VDF_DEAD | VDF_TEXTMODE)) != 0)
|
|
goto out;
|
|
|
|
vt_draw_logo_cpus = 0;
|
|
VT_UNLOCK(vd);
|
|
|
|
vt_termsize(vd, vf, &size);
|
|
vt_winsize(vd, vf, &wsz);
|
|
|
|
/* Resize screen buffer and terminal. */
|
|
terminal_mute(tm, 1);
|
|
vtbuf_grow(&vw->vw_buf, &size, vw->vw_buf.vb_history_size);
|
|
terminal_set_winsize_blank(tm, &wsz, 0, NULL);
|
|
terminal_set_cursor(tm, &vw->vw_buf.vb_cursor);
|
|
terminal_mute(tm, 0);
|
|
|
|
VT_LOCK(vd);
|
|
vt_compute_drawable_area(vw);
|
|
|
|
if (vd->vd_curwindow == vw) {
|
|
vd->vd_flags |= VDF_INVALID;
|
|
vt_resume_flush_timer(vd, 0);
|
|
}
|
|
|
|
out:
|
|
VT_UNLOCK(vd);
|
|
}
|
|
|
|
static void
|
|
vt_init_logos(void *dummy)
|
|
{
|
|
struct vt_device *vd;
|
|
struct vt_window *vw;
|
|
struct terminal *tm;
|
|
struct vt_font *vf;
|
|
struct winsize wsz;
|
|
term_pos_t size;
|
|
|
|
if (!vty_enabled(VTY_VT))
|
|
return;
|
|
if (!vt_splash_cpu)
|
|
return;
|
|
|
|
tm = &vt_consterm;
|
|
vw = tm->tm_softc;
|
|
if (vw == NULL)
|
|
return;
|
|
vd = vw->vw_device;
|
|
if (vd == NULL)
|
|
return;
|
|
vf = vw->vw_font;
|
|
if (vf == NULL)
|
|
return;
|
|
|
|
VT_LOCK(vd);
|
|
KASSERT((vd->vd_flags & VDF_INITIALIZED) != 0,
|
|
("vd %p not initialized", vd));
|
|
|
|
if ((vd->vd_flags & (VDF_DEAD | VDF_TEXTMODE)) != 0)
|
|
goto out;
|
|
if (vd->vd_height <= vt_logo_sprite_height)
|
|
goto out;
|
|
|
|
vt_draw_logo_cpus = 1;
|
|
VT_UNLOCK(vd);
|
|
|
|
vt_termsize(vd, vf, &size);
|
|
vt_winsize(vd, vf, &wsz);
|
|
|
|
/* Resize screen buffer and terminal. */
|
|
terminal_mute(tm, 1);
|
|
vtbuf_grow(&vw->vw_buf, &size, vw->vw_buf.vb_history_size);
|
|
terminal_set_winsize_blank(tm, &wsz, 0, NULL);
|
|
terminal_set_cursor(tm, &vw->vw_buf.vb_cursor);
|
|
terminal_mute(tm, 0);
|
|
|
|
VT_LOCK(vd);
|
|
vt_compute_drawable_area(vw);
|
|
|
|
if (vd->vd_curwindow == vw) {
|
|
vd->vd_flags |= VDF_INVALID;
|
|
vt_resume_flush_timer(vd, 0);
|
|
}
|
|
|
|
callout_init(&vt_splash_cpu_callout, 1);
|
|
callout_reset(&vt_splash_cpu_callout, vt_splash_cpu_duration * hz,
|
|
vt_fini_logos, NULL);
|
|
|
|
out:
|
|
VT_UNLOCK(vd);
|
|
}
|
|
SYSINIT(vt_logos, SI_SUB_CPU + 1, SI_ORDER_ANY, vt_init_logos, NULL);
|