loader: implement framebuffer console

Draw console on efi.
Add vbe framebuffer for BIOS loader (vbe off, vbe on, vbe list,
vbe set xxx).
autoload font (/boot/fonts) based on resolution and font size.
Add command loadfont (set font by file) and
variable screen.font (set font by size). Pass loaded font to kernel.

Export variables:
screen.height
screen.width
screen.depth

Add gfx primitives to draw the screen and put png image on the screen.
Rework menu draw to iterate list of consoles to enamble device specific
output.

Probably something else I forgot...

Relnotes: yes
Differential Revision: https://reviews.freebsd.org/D27420
This commit is contained in:
Toomas Soome 2020-12-21 07:31:16 +02:00
parent bd03acedb8
commit 3630506b9d
51 changed files with 6073 additions and 404 deletions

View File

@ -25,6 +25,8 @@ S.${MK_FORTH}+= forth
S.${MK_LOADER_LUA}+= liblua S.${MK_LOADER_LUA}+= liblua
S.${MK_LOADER_LUA}+= lua S.${MK_LOADER_LUA}+= lua
S.yes+= defaults S.yes+= defaults
S.yes+= fonts
S.yes+= images
S.yes+= man S.yes+= man
.if ${MK_FORTH} != "no" .if ${MK_FORTH} != "no"

View File

@ -32,6 +32,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/queue.h> #include <sys/queue.h>
#include <sys/linker_set.h> #include <sys/linker_set.h>
#include <stdbool.h>
#include "readin.h" #include "readin.h"
@ -119,6 +120,8 @@ struct console
}; };
extern struct console *consoles[]; extern struct console *consoles[];
void cons_probe(void); void cons_probe(void);
bool cons_update_mode(bool);
void autoload_font(bool);
/* /*
* Plug-and-play enumerator/configurator interface. * Plug-and-play enumerator/configurator interface.
@ -258,6 +261,8 @@ int file_addmodule(struct preloaded_file *, char *, int,
struct kernel_module **); struct kernel_module **);
void file_removemetadata(struct preloaded_file *fp); void file_removemetadata(struct preloaded_file *fp);
vm_offset_t build_font_module(vm_offset_t);
/* MI module loaders */ /* MI module loaders */
#ifdef __elfN #ifdef __elfN
/* Relocation types. */ /* Relocation types. */

2641
stand/common/gfx_fb.c Normal file

File diff suppressed because it is too large Load Diff

274
stand/common/gfx_fb.h Normal file
View File

@ -0,0 +1,274 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright 2020 Toomas Soome
* Copyright 2020 RackTop Systems, Inc.
*
* 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.
*
* $FreeBSD$
*/
#ifndef _GFX_FB_H
#define _GFX_FB_H
#include <sys/font.h>
#include <teken.h>
#include <stdbool.h>
#include <machine/metadata.h>
#include <pnglite.h>
#ifdef __cplusplus
extern "C" {
#endif
#define EDID_MAGIC { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 }
struct edid_header {
uint8_t header[8]; /* fixed header pattern */
uint16_t manufacturer_id;
uint16_t product_code;
uint32_t serial_number;
uint8_t week_of_manufacture;
uint8_t year_of_manufacture;
uint8_t version;
uint8_t revision;
};
struct edid_basic_display_parameters {
uint8_t video_input_parameters;
uint8_t max_horizontal_image_size;
uint8_t max_vertical_image_size;
uint8_t display_gamma;
uint8_t supported_features;
};
struct edid_chromaticity_coordinates {
uint8_t red_green_lo;
uint8_t blue_white_lo;
uint8_t red_x_hi;
uint8_t red_y_hi;
uint8_t green_x_hi;
uint8_t green_y_hi;
uint8_t blue_x_hi;
uint8_t blue_y_hi;
uint8_t white_x_hi;
uint8_t white_y_hi;
};
struct edid_detailed_timings {
uint16_t pixel_clock;
uint8_t horizontal_active_lo;
uint8_t horizontal_blanking_lo;
uint8_t horizontal_hi;
uint8_t vertical_active_lo;
uint8_t vertical_blanking_lo;
uint8_t vertical_hi;
uint8_t horizontal_sync_offset_lo;
uint8_t horizontal_sync_pulse_width_lo;
uint8_t vertical_sync_lo;
uint8_t sync_hi;
uint8_t horizontal_image_size_lo;
uint8_t vertical_image_size_lo;
uint8_t image_size_hi;
uint8_t horizontal_border;
uint8_t vertical_border;
uint8_t features;
};
struct vesa_edid_info {
struct edid_header header;
struct edid_basic_display_parameters display;
#define EDID_FEATURE_PREFERRED_TIMING_MODE (1 << 1)
struct edid_chromaticity_coordinates chromaticity;
uint8_t established_timings_1;
uint8_t established_timings_2;
uint8_t manufacturer_reserved_timings;
uint16_t standard_timings[8];
struct edid_detailed_timings detailed_timings[4];
uint8_t number_of_extensions;
uint8_t checksum;
} __packed;
#define STD_TIMINGS 8
#define DET_TIMINGS 4
#define HSIZE(x) (((x & 0xff) + 31) * 8)
#define RATIO(x) ((x & 0xC000) >> 14)
#define RATIO1_1 0
/* EDID Ver. 1.3 redefined this */
#define RATIO16_10 RATIO1_1
#define RATIO4_3 1
#define RATIO5_4 2
#define RATIO16_9 3
/*
* Number of pixels and lines is 12-bit int, valid values 0-4095.
*/
#define EDID_MAX_PIXELS 4095
#define EDID_MAX_LINES 4095
#define GET_EDID_INFO_WIDTH(edid_info, timings_num) \
((edid_info)->detailed_timings[(timings_num)].horizontal_active_lo | \
(((uint32_t)(edid_info)->detailed_timings[(timings_num)].horizontal_hi & \
0xf0) << 4))
#define GET_EDID_INFO_HEIGHT(edid_info, timings_num) \
((edid_info)->detailed_timings[(timings_num)].vertical_active_lo | \
(((uint32_t)(edid_info)->detailed_timings[(timings_num)].vertical_hi & \
0xf0) << 4))
struct resolution {
uint32_t width;
uint32_t height;
TAILQ_ENTRY(resolution) next;
};
typedef TAILQ_HEAD(edid_resolution, resolution) edid_res_list_t;
struct vesa_flat_panel_info {
uint16_t HSize; /* Horizontal Size in Pixels */
uint16_t VSize; /* Vertical Size in Lines */
uint16_t FPType; /* Flat Panel Type */
uint8_t RedBPP; /* Red Bits Per Primary */
uint8_t GreenBPP; /* Green Bits Per Primary */
uint8_t BlueBPP; /* Blue Bits Per Primary */
uint8_t ReservedBPP; /* Reserved Bits Per Primary */
uint32_t RsvdOffScrnMemSize; /* Size in KB of Offscreen Memory */
uint32_t RsvdOffScrnMemPtr; /* Pointer to reserved offscreen memory */
uint8_t Reserved[14]; /* remainder of FPInfo */
} __packed;
#define COLOR_FORMAT_VGA 0
#define COLOR_FORMAT_RGB 1
#define NCOLORS 16
#define NCMAP 256
extern uint32_t cmap[NCMAP];
enum FB_TYPE {
FB_TEXT = -1,
FB_GOP,
FB_UGA,
FB_VBE
};
enum COLOR_TYPE {
CT_INDEXED,
CT_RGB
};
struct gen_fb {
uint64_t fb_addr;
uint64_t fb_size;
uint32_t fb_height;
uint32_t fb_width;
uint32_t fb_stride;
uint32_t fb_mask_red;
uint32_t fb_mask_green;
uint32_t fb_mask_blue;
uint32_t fb_mask_reserved;
uint32_t fb_bpp;
};
typedef struct teken_gfx {
enum FB_TYPE tg_fb_type;
enum COLOR_TYPE tg_ctype;
unsigned tg_mode;
teken_t tg_teken; /* Teken core */
teken_pos_t tg_cursor; /* Where cursor was drawn */
bool tg_cursor_visible;
teken_pos_t tg_tp; /* Terminal dimensions */
teken_pos_t tg_origin; /* Point of origin in pixels */
uint8_t *tg_glyph; /* Memory for glyph */
size_t tg_glyph_size;
struct vt_font tg_font;
struct gen_fb tg_fb;
teken_funcs_t *tg_functions;
void *tg_private;
} teken_gfx_t;
extern font_list_t fonts;
extern teken_gfx_t gfx_state;
typedef enum {
GfxFbBltVideoFill,
GfxFbBltVideoToBltBuffer,
GfxFbBltBufferToVideo,
GfxFbBltVideoToVideo,
GfxFbBltOperationMax,
} GFXFB_BLT_OPERATION;
int gfxfb_blt(void *, GFXFB_BLT_OPERATION, uint32_t, uint32_t,
uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
int generate_cons_palette(uint32_t *, int, uint32_t, int, uint32_t, int,
uint32_t, int);
bool console_update_mode(bool);
void setup_font(teken_gfx_t *, teken_unit_t, teken_unit_t);
uint8_t *font_lookup(const struct vt_font *, teken_char_t,
const teken_attr_t *);
void bios_text_font(bool);
/* teken callbacks. */
tf_cursor_t gfx_fb_cursor;
tf_putchar_t gfx_fb_putchar;
tf_fill_t gfx_fb_fill;
tf_copy_t gfx_fb_copy;
tf_param_t gfx_fb_param;
/* Screen buffer element */
struct text_pixel {
teken_char_t c;
teken_attr_t a;
};
extern const int cons_to_vga_colors[NCOLORS];
/* Screen buffer to track changes on the terminal screen. */
extern struct text_pixel *screen_buffer;
bool is_same_pixel(struct text_pixel *, struct text_pixel *);
bool gfx_get_edid_resolution(struct vesa_edid_info *, edid_res_list_t *);
void gfx_framework_init(void);
void gfx_fb_cons_display(uint32_t, uint32_t, uint32_t, uint32_t, void *);
void gfx_fb_setpixel(uint32_t, uint32_t);
void gfx_fb_drawrect(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
void gfx_term_drawrect(uint32_t, uint32_t, uint32_t, uint32_t);
void gfx_fb_line(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
void gfx_fb_bezier(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t,
uint32_t);
#define FL_PUTIMAGE_BORDER 0x1
#define FL_PUTIMAGE_NOSCROLL 0x2
#define FL_PUTIMAGE_DEBUG 0x80
int gfx_fb_putimage(png_t *, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
bool gfx_parse_mode_str(char *, int *, int *, int *);
void term_image_display(teken_gfx_t *, const teken_rect_t *);
void reset_font_flags(void);
#ifdef __cplusplus
}
#endif
#endif /* _GFX_FB_H */

View File

@ -38,6 +38,8 @@ __FBSDID("$FreeBSD$");
#include <sys/module.h> #include <sys/module.h>
#include <sys/queue.h> #include <sys/queue.h>
#include <sys/stdint.h> #include <sys/stdint.h>
#include <sys/font.h>
#include <gfx_fb.h>
#if defined(LOADER_FDT_SUPPORT) #if defined(LOADER_FDT_SUPPORT)
#include <fdt_platform.h> #include <fdt_platform.h>
@ -91,7 +93,6 @@ static char *kld_ext_list[] = {
NULL NULL
}; };
/* /*
* load an object, either a disk file or code module. * load an object, either a disk file or code module.
* *
@ -616,6 +617,92 @@ file_load_dependencies(struct preloaded_file *base_file)
return (error); return (error);
} }
vm_offset_t
build_font_module(vm_offset_t addr)
{
vt_font_bitmap_data_t *bd;
struct vt_font *fd;
struct preloaded_file *fp;
size_t size;
uint32_t checksum;
int i;
struct font_info fi;
struct fontlist *fl;
uint64_t fontp;
if (STAILQ_EMPTY(&fonts))
return (addr);
/* We can't load first */
if ((file_findfile(NULL, NULL)) == NULL) {
printf("Can not load font module: %s\n",
"the kernel is not loaded");
return (addr);
}
/* helper pointers */
bd = NULL;
STAILQ_FOREACH(fl, &fonts, font_next) {
if (gfx_state.tg_font.vf_width == fl->font_data->vfbd_width &&
gfx_state.tg_font.vf_height == fl->font_data->vfbd_height) {
/*
* Kernel does have better built in font.
*/
if (fl->font_flags == FONT_BUILTIN)
return (addr);
bd = fl->font_data;
break;
}
}
if (bd == NULL)
return (addr);
fd = bd->vfbd_font;
fi.fi_width = fd->vf_width;
checksum = fi.fi_width;
fi.fi_height = fd->vf_height;
checksum += fi.fi_height;
fi.fi_bitmap_size = bd->vfbd_uncompressed_size;
checksum += fi.fi_bitmap_size;
size = roundup2(sizeof (struct font_info), 8);
for (i = 0; i < VFNT_MAPS; i++) {
fi.fi_map_count[i] = fd->vf_map_count[i];
checksum += fi.fi_map_count[i];
size += fd->vf_map_count[i] * sizeof (struct vfnt_map);
size += roundup2(size, 8);
}
size += bd->vfbd_uncompressed_size;
fi.fi_checksum = -checksum;
fp = file_findfile(NULL, "elf kernel");
if (fp == NULL)
fp = file_findfile(NULL, "elf64 kernel");
if (fp == NULL)
panic("can't find kernel file");
fontp = addr;
addr += archsw.arch_copyin(&fi, addr, sizeof (struct font_info));
addr = roundup2(addr, 8);
/* Copy maps. */
for (i = 0; i < VFNT_MAPS; i++) {
if (fd->vf_map_count[i] != 0) {
addr += archsw.arch_copyin(fd->vf_map[i], addr,
fd->vf_map_count[i] * sizeof (struct vfnt_map));
addr = roundup2(addr, 8);
}
}
/* Copy the bitmap. */
addr += archsw.arch_copyin(fd->vf_bytes, addr, fi.fi_bitmap_size);
/* Looks OK so far; populate control structure */
file_addmetadata(fp, MODINFOMD_FONT, sizeof(fontp), &fontp);
return (addr);
}
#ifdef LOADER_VERIEXEC_VECTX #ifdef LOADER_VERIEXEC_VECTX
#define VECTX_HANDLE(fd) vctx #define VECTX_HANDLE(fd) vctx

View File

@ -238,7 +238,9 @@ replacing it with
.Dq spinning .Dq spinning
character (useful for embedded products and such). character (useful for embedded products and such).
.It Va efi_max_resolution .It Va efi_max_resolution
Specify the maximum desired resolution for the EFI console. .It Va vbe_max_resolution
Specify the maximum desired resolution for the EFI or VESA BIOS Extension (VBE)
framebuffer console.
The following values are accepted: The following values are accepted:
.Bl -column "WidthxHeight" .Bl -column "WidthxHeight"
.It Sy Value Ta Sy Resolution .It Sy Value Ta Sy Resolution

View File

@ -108,7 +108,6 @@ void efi_time_init(void);
void efi_time_fini(void); void efi_time_fini(void);
int parse_uefi_con_out(void); int parse_uefi_con_out(void);
bool efi_cons_update_mode(void);
EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab); EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab);
EFI_STATUS main(int argc, CHAR16 *argv[]); EFI_STATUS main(int argc, CHAR16 *argv[]);

View File

@ -49,7 +49,7 @@ CFLAGS+= -fPIC -mno-red-zone
.endif .endif
CFLAGS+= -I${EFIINC} CFLAGS+= -I${EFIINC}
CFLAGS+= -I${EFIINCMD} CFLAGS+= -I${EFIINCMD}
CFLAGS.efi_console.c+= -I${SRCTOP}/sys/teken CFLAGS.efi_console.c+= -I${SRCTOP}/sys/teken -I${SRCTOP}/contrib/pnglite
CFLAGS.teken.c+= -I${SRCTOP}/sys/teken CFLAGS.teken.c+= -I${SRCTOP}/sys/teken
.if ${MK_LOADER_ZFS} != "no" .if ${MK_LOADER_ZFS} != "no"
CFLAGS+= -I${ZFSSRC} CFLAGS+= -I${ZFSSRC}

View File

@ -27,17 +27,22 @@
#include <sys/cdefs.h> #include <sys/cdefs.h>
__FBSDID("$FreeBSD$"); __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <efi.h> #include <efi.h>
#include <efilib.h> #include <efilib.h>
#include <teken.h> #include <teken.h>
#include <sys/reboot.h> #include <sys/reboot.h>
#include <machine/metadata.h>
#include <gfx_fb.h>
#include "bootstrap.h" #include "bootstrap.h"
extern EFI_GUID gop_guid;
extern int efi_find_framebuffer(struct efi_fb *efifb);
static EFI_GUID simple_input_ex_guid = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID; static EFI_GUID simple_input_ex_guid = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
static SIMPLE_TEXT_OUTPUT_INTERFACE *conout; static SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
static SIMPLE_INPUT_INTERFACE *conin; static SIMPLE_INPUT_INTERFACE *conin;
static EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *coninex; static EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *coninex;
static bool efi_started;
static int mode; /* Does ConOut have serial console? */ static int mode; /* Does ConOut have serial console? */
@ -59,6 +64,9 @@ void HO(void);
void end_term(void); void end_term(void);
#endif #endif
#define TEXT_ROWS 24
#define TEXT_COLS 80
static tf_bell_t efi_cons_bell; static tf_bell_t efi_cons_bell;
static tf_cursor_t efi_text_cursor; static tf_cursor_t efi_text_cursor;
static tf_putchar_t efi_text_putchar; static tf_putchar_t efi_text_putchar;
@ -77,16 +85,16 @@ static teken_funcs_t tf = {
.tf_respond = efi_cons_respond, .tf_respond = efi_cons_respond,
}; };
teken_t teken; static teken_funcs_t tfx = {
teken_pos_t tp; .tf_bell = efi_cons_bell,
.tf_cursor = gfx_fb_cursor,
struct text_pixel { .tf_putchar = gfx_fb_putchar,
teken_char_t c; .tf_fill = gfx_fb_fill,
teken_attr_t a; .tf_copy = gfx_fb_copy,
.tf_param = gfx_fb_param,
.tf_respond = efi_cons_respond,
}; };
static struct text_pixel *buffer;
#define KEYBUFSZ 10 #define KEYBUFSZ 10
static unsigned keybuf[KEYBUFSZ]; /* keybuf for extended codes */ static unsigned keybuf[KEYBUFSZ]; /* keybuf for extended codes */
static int key_pending; static int key_pending;
@ -116,6 +124,7 @@ void efi_cons_putchar(int);
int efi_cons_getchar(void); int efi_cons_getchar(void);
void efi_cons_efiputchar(int); void efi_cons_efiputchar(int);
int efi_cons_poll(void); int efi_cons_poll(void);
static void cons_draw_frame(teken_attr_t *);
struct console efi_console = { struct console efi_console = {
"efi", "efi",
@ -128,6 +137,28 @@ struct console efi_console = {
efi_cons_poll efi_cons_poll
}; };
/*
* This function is used to mark a rectangular image area so the scrolling
* will know we need to copy the data from there.
*/
void
term_image_display(teken_gfx_t *state, const teken_rect_t *r)
{
teken_pos_t p;
int idx;
for (p.tp_row = r->tr_begin.tp_row;
p.tp_row < r->tr_end.tp_row; p.tp_row++) {
for (p.tp_col = r->tr_begin.tp_col;
p.tp_col < r->tr_end.tp_col; p.tp_col++) {
idx = p.tp_col + p.tp_row * state->tg_tp.tp_col;
if (idx >= state->tg_tp.tp_col * state->tg_tp.tp_row)
return;
screen_buffer[idx].a.ta_format |= TF_IMAGE;
}
}
}
/* /*
* Not implemented. * Not implemented.
*/ */
@ -137,33 +168,30 @@ efi_cons_bell(void *s __unused)
} }
static void static void
efi_text_cursor(void *s __unused, const teken_pos_t *p) efi_text_cursor(void *arg, const teken_pos_t *p)
{ {
UINTN row, col; teken_gfx_t *state = arg;
UINTN col, row;
(void) conout->QueryMode(conout, conout->Mode->Mode, &col, &row);
if (p->tp_col == col)
col = p->tp_col - 1;
else
col = p->tp_col;
if (p->tp_row == row)
row = p->tp_row - 1;
else
row = p->tp_row; row = p->tp_row;
if (p->tp_row >= state->tg_tp.tp_row)
row = state->tg_tp.tp_row - 1;
col = p->tp_col;
if (p->tp_col >= state->tg_tp.tp_col)
col = state->tg_tp.tp_col - 1;
conout->SetCursorPosition(conout, col, row); conout->SetCursorPosition(conout, col, row);
} }
static void static void
efi_text_printchar(const teken_pos_t *p, bool autoscroll) efi_text_printchar(teken_gfx_t *state, const teken_pos_t *p, bool autoscroll)
{ {
UINTN a, attr; UINTN a, attr;
struct text_pixel *px; struct text_pixel *px;
teken_color_t fg, bg, tmp; teken_color_t fg, bg, tmp;
px = buffer + p->tp_col + p->tp_row * tp.tp_col; px = screen_buffer + p->tp_col + p->tp_row * state->tg_tp.tp_col;
a = conout->Mode->Attribute; a = conout->Mode->Attribute;
fg = teken_256to16(px->a.ta_fgcolor); fg = teken_256to16(px->a.ta_fgcolor);
@ -184,10 +212,10 @@ efi_text_printchar(const teken_pos_t *p, bool autoscroll)
conout->SetCursorPosition(conout, p->tp_col, p->tp_row); conout->SetCursorPosition(conout, p->tp_col, p->tp_row);
/* to prvent autoscroll, skip print of lower right char */ /* to prevent autoscroll, skip print of lower right char */
if (!autoscroll && if (!autoscroll &&
p->tp_row == tp.tp_row - 1 && p->tp_row == state->tg_tp.tp_row - 1 &&
p->tp_col == tp.tp_col - 1) p->tp_col == state->tg_tp.tp_col - 1)
return; return;
(void) conout->SetAttribute(conout, attr); (void) conout->SetAttribute(conout, attr);
@ -196,58 +224,80 @@ efi_text_printchar(const teken_pos_t *p, bool autoscroll)
} }
static void static void
efi_text_putchar(void *s __unused, const teken_pos_t *p, teken_char_t c, efi_text_putchar(void *s, const teken_pos_t *p, teken_char_t c,
const teken_attr_t *a) const teken_attr_t *a)
{ {
teken_gfx_t *state = s;
EFI_STATUS status; EFI_STATUS status;
int idx; int idx;
idx = p->tp_col + p->tp_row * tp.tp_col; idx = p->tp_col + p->tp_row * state->tg_tp.tp_col;
buffer[idx].c = c; if (idx >= state->tg_tp.tp_col * state->tg_tp.tp_row)
buffer[idx].a = *a; return;
efi_text_printchar(p, false);
screen_buffer[idx].c = c;
screen_buffer[idx].a = *a;
efi_text_printchar(s, p, false);
} }
static void static void
efi_text_fill(void *s, const teken_rect_t *r, teken_char_t c, efi_text_fill(void *arg, const teken_rect_t *r, teken_char_t c,
const teken_attr_t *a) const teken_attr_t *a)
{ {
teken_gfx_t *state = arg;
teken_pos_t p; teken_pos_t p;
UINTN row, col;
(void) conout->QueryMode(conout, conout->Mode->Mode, &col, &row);
if (state->tg_cursor_visible)
conout->EnableCursor(conout, FALSE); conout->EnableCursor(conout, FALSE);
for (p.tp_row = r->tr_begin.tp_row; p.tp_row < r->tr_end.tp_row; for (p.tp_row = r->tr_begin.tp_row; p.tp_row < r->tr_end.tp_row;
p.tp_row++) p.tp_row++)
for (p.tp_col = r->tr_begin.tp_col; for (p.tp_col = r->tr_begin.tp_col;
p.tp_col < r->tr_end.tp_col; p.tp_col++) p.tp_col < r->tr_end.tp_col; p.tp_col++)
efi_text_putchar(s, &p, c, a); efi_text_putchar(state, &p, c, a);
if (state->tg_cursor_visible)
conout->EnableCursor(conout, TRUE); conout->EnableCursor(conout, TRUE);
} }
static bool static void
efi_same_pixel(struct text_pixel *px1, struct text_pixel *px2) efi_text_copy_line(teken_gfx_t *state, int ncol, teken_pos_t *s,
teken_pos_t *d, bool scroll)
{ {
if (px1->c != px2->c) unsigned soffset, doffset;
return (false); teken_pos_t sp, dp;
int x;
if (px1->a.ta_format != px2->a.ta_format) soffset = s->tp_col + s->tp_row * state->tg_tp.tp_col;
return (false); doffset = d->tp_col + d->tp_row * state->tg_tp.tp_col;
if (px1->a.ta_fgcolor != px2->a.ta_fgcolor)
return (false);
if (px1->a.ta_bgcolor != px2->a.ta_bgcolor)
return (false);
return (true); sp = *s;
dp = *d;
for (x = 0; x < ncol; x++) {
sp.tp_col = s->tp_col + x;
dp.tp_col = d->tp_col + x;
if (!is_same_pixel(&screen_buffer[soffset + x],
&screen_buffer[doffset + x])) {
screen_buffer[doffset + x] =
screen_buffer[soffset + x];
if (!scroll)
efi_text_printchar(state, &dp, false);
} else if (scroll) {
/* Draw last char and trigger scroll. */
if (dp.tp_col + 1 == state->tg_tp.tp_col &&
dp.tp_row + 1 == state->tg_tp.tp_row) {
efi_text_printchar(state, &dp, true);
}
}
}
} }
static void static void
efi_text_copy(void *ptr __unused, const teken_rect_t *r, const teken_pos_t *p) efi_text_copy(void *arg, const teken_rect_t *r, const teken_pos_t *p)
{ {
int srow, drow; teken_gfx_t *state = arg;
int nrow, ncol, x, y; /* Has to be signed - >= 0 comparison */ unsigned doffset, soffset;
teken_pos_t d, s; teken_pos_t d, s;
int nrow, ncol, x, y; /* Has to be signed - >= 0 comparison */
bool scroll = false; bool scroll = false;
/* /*
@ -262,90 +312,47 @@ efi_text_copy(void *ptr __unused, const teken_rect_t *r, const teken_pos_t *p)
* Check if we do copy whole screen. * Check if we do copy whole screen.
*/ */
if (p->tp_row == 0 && p->tp_col == 0 && if (p->tp_row == 0 && p->tp_col == 0 &&
nrow == tp.tp_row - 2 && ncol == tp.tp_col - 2) nrow == state->tg_tp.tp_row - 2 && ncol == state->tg_tp.tp_col - 2)
scroll = true; scroll = true;
soffset = r->tr_begin.tp_col + r->tr_begin.tp_row * state->tg_tp.tp_col;
doffset = p->tp_col + p->tp_row * state->tg_tp.tp_col;
/* remove the cursor */
if (state->tg_cursor_visible)
conout->EnableCursor(conout, FALSE); conout->EnableCursor(conout, FALSE);
if (p->tp_row < r->tr_begin.tp_row) {
/* Copy from bottom to top. */
for (y = 0; y < nrow; y++) {
d.tp_row = p->tp_row + y;
s.tp_row = r->tr_begin.tp_row + y;
drow = d.tp_row * tp.tp_col;
srow = s.tp_row * tp.tp_col;
for (x = 0; x < ncol; x++) {
d.tp_col = p->tp_col + x;
s.tp_col = r->tr_begin.tp_col + x;
if (!efi_same_pixel(
&buffer[d.tp_col + drow],
&buffer[s.tp_col + srow])) {
buffer[d.tp_col + drow] =
buffer[s.tp_col + srow];
if (!scroll)
efi_text_printchar(&d, false);
} else if (scroll) {
/* /*
* Draw last char and trigger * Copy line by line.
* scroll.
*/ */
if (y == nrow - 1 && if (doffset <= soffset) {
x == ncol - 1) { s = r->tr_begin;
efi_text_printchar(&d, true); d = *p;
} for (y = 0; y < nrow; y++) {
} s.tp_row = r->tr_begin.tp_row + y;
} d.tp_row = p->tp_row + y;
efi_text_copy_line(state, ncol, &s, &d, scroll);
} }
} else { } else {
/* Copy from top to bottom. */
if (p->tp_col < r->tr_begin.tp_col) {
/* Copy from right to left. */
for (y = nrow - 1; y >= 0; y--) { for (y = nrow - 1; y >= 0; y--) {
d.tp_row = p->tp_row + y;
s.tp_row = r->tr_begin.tp_row + y; s.tp_row = r->tr_begin.tp_row + y;
drow = d.tp_row * tp.tp_col;
srow = s.tp_row * tp.tp_col;
for (x = 0; x < ncol; x++) {
d.tp_col = p->tp_col + x;
s.tp_col = r->tr_begin.tp_col + x;
if (!efi_same_pixel(
&buffer[d.tp_col + drow],
&buffer[s.tp_col + srow])) {
buffer[d.tp_col + drow] =
buffer[s.tp_col + srow];
efi_text_printchar(&d, false);
}
}
}
} else {
/* Copy from left to right. */
for (y = nrow - 1; y >= 0; y--) {
d.tp_row = p->tp_row + y; d.tp_row = p->tp_row + y;
s.tp_row = r->tr_begin.tp_row + y;
drow = d.tp_row * tp.tp_col;
srow = s.tp_row * tp.tp_col;
for (x = ncol - 1; x >= 0; x--) {
d.tp_col = p->tp_col + x;
s.tp_col = r->tr_begin.tp_col + x;
if (!efi_same_pixel( efi_text_copy_line(state, ncol, &s, &d, false);
&buffer[d.tp_col + drow],
&buffer[s.tp_col + srow])) {
buffer[d.tp_col + drow] =
buffer[s.tp_col + srow];
efi_text_printchar(&d, false);
}
}
}
} }
} }
/* display the cursor */
if (state->tg_cursor_visible)
conout->EnableCursor(conout, TRUE); conout->EnableCursor(conout, TRUE);
} }
static void static void
efi_text_param(void *s __unused, int cmd, unsigned int value) efi_text_param(void *arg, int cmd, unsigned int value)
{ {
teken_gfx_t *state = arg;
switch (cmd) { switch (cmd) {
case TP_SETLOCALCURSOR: case TP_SETLOCALCURSOR:
/* /*
@ -357,10 +364,13 @@ efi_text_param(void *s __unused, int cmd, unsigned int value)
value = (value == 1) ? 0 : 1; value = (value == 1) ? 0 : 1;
/* FALLTHROUGH */ /* FALLTHROUGH */
case TP_SHOWCURSOR: case TP_SHOWCURSOR:
if (value == 1) if (value != 0) {
conout->EnableCursor(conout, TRUE); conout->EnableCursor(conout, TRUE);
else state->tg_cursor_visible = true;
} else {
conout->EnableCursor(conout, FALSE); conout->EnableCursor(conout, FALSE);
state->tg_cursor_visible = false;
}
break; break;
default: default:
/* Not yet implemented */ /* Not yet implemented */
@ -470,7 +480,7 @@ efi_set_colors(struct env_var *ev, int flags, const void *value)
evalue = value; evalue = value;
} }
ap = teken_get_defattr(&teken); ap = teken_get_defattr(&gfx_state.tg_teken);
a = *ap; a = *ap;
if (strcmp(ev->ev_name, "teken.fg_color") == 0) { if (strcmp(ev->ev_name, "teken.fg_color") == 0) {
/* is it already set? */ /* is it already set? */
@ -484,8 +494,15 @@ efi_set_colors(struct env_var *ev, int flags, const void *value)
return (CMD_OK); return (CMD_OK);
a.ta_bgcolor = val; a.ta_bgcolor = val;
} }
/* Improve visibility */
if (a.ta_bgcolor == TC_WHITE)
a.ta_bgcolor |= TC_LIGHT;
teken_set_defattr(&gfx_state.tg_teken, &a);
cons_draw_frame(&a);
env_setenv(ev->ev_name, flags | EV_NOHOOK, evalue, NULL, NULL); env_setenv(ev->ev_name, flags | EV_NOHOOK, evalue, NULL, NULL);
teken_set_defattr(&teken, &a); teken_input(&gfx_state.tg_teken, "\e[2J", 4);
return (CMD_OK); return (CMD_OK);
} }
@ -823,19 +840,100 @@ efi_term_emu(int c)
#endif #endif
} }
static int
env_screen_nounset(struct env_var *ev __unused)
{
if (gfx_state.tg_fb_type == FB_TEXT)
return (0);
return (EPERM);
}
static void
cons_draw_frame(teken_attr_t *a)
{
teken_attr_t attr = *a;
teken_color_t fg = a->ta_fgcolor;
attr.ta_fgcolor = attr.ta_bgcolor;
teken_set_defattr(&gfx_state.tg_teken, &attr);
gfx_fb_drawrect(0, 0, gfx_state.tg_fb.fb_width,
gfx_state.tg_origin.tp_row, 1);
gfx_fb_drawrect(0,
gfx_state.tg_fb.fb_height - gfx_state.tg_origin.tp_row - 1,
gfx_state.tg_fb.fb_width, gfx_state.tg_fb.fb_height, 1);
gfx_fb_drawrect(0, gfx_state.tg_origin.tp_row,
gfx_state.tg_origin.tp_col,
gfx_state.tg_fb.fb_height - gfx_state.tg_origin.tp_row - 1, 1);
gfx_fb_drawrect(
gfx_state.tg_fb.fb_width - gfx_state.tg_origin.tp_col - 1,
gfx_state.tg_origin.tp_row, gfx_state.tg_fb.fb_width,
gfx_state.tg_fb.fb_height, 1);
attr.ta_fgcolor = fg;
teken_set_defattr(&gfx_state.tg_teken, &attr);
}
bool bool
efi_cons_update_mode(void) cons_update_mode(bool use_gfx_mode)
{ {
UINTN cols, rows; UINTN cols, rows;
const teken_attr_t *a; const teken_attr_t *a;
teken_attr_t attr; teken_attr_t attr;
EFI_STATUS status; EFI_STATUS status;
char env[8], *ptr; EFI_GRAPHICS_OUTPUT *gop = NULL;
struct efi_fb efifb;
char env[10], *ptr;
if (use_gfx_mode == true) {
gfx_state.tg_fb_type = FB_GOP;
if (gfx_state.tg_private == NULL) {
(void) BS->LocateProtocol(&gop_guid, NULL,
(void **)&gop);
gfx_state.tg_private = gop;
} else {
gop = gfx_state.tg_private;
}
/*
* We have FB but no GOP - it must be UGA.
*/
if (gop == NULL)
gfx_state.tg_fb_type = FB_UGA;
if (efi_find_framebuffer(&efifb) == 0) {
int roff, goff, boff;
gfx_state.tg_fb.fb_addr = efifb.fb_addr;
gfx_state.tg_fb.fb_size = efifb.fb_size;
gfx_state.tg_fb.fb_height = efifb.fb_height;
gfx_state.tg_fb.fb_width = efifb.fb_width;
gfx_state.tg_fb.fb_stride = efifb.fb_stride;
gfx_state.tg_fb.fb_mask_red = efifb.fb_mask_red;
gfx_state.tg_fb.fb_mask_green = efifb.fb_mask_green;
gfx_state.tg_fb.fb_mask_blue = efifb.fb_mask_blue;
gfx_state.tg_fb.fb_mask_reserved =
efifb.fb_mask_reserved;
roff = ffs(efifb.fb_mask_red) - 1;
goff = ffs(efifb.fb_mask_green) - 1;
boff = ffs(efifb.fb_mask_blue) - 1;
(void) generate_cons_palette(cmap, COLOR_FORMAT_RGB,
efifb.fb_mask_red >> roff, roff,
efifb.fb_mask_green >> goff, goff,
efifb.fb_mask_blue >> boff, boff);
gfx_state.tg_fb.fb_bpp = fls(
efifb.fb_mask_red | efifb.fb_mask_green |
efifb.fb_mask_blue | efifb.fb_mask_reserved);
}
} else {
gfx_state.tg_fb_type = FB_TEXT;
}
status = conout->QueryMode(conout, conout->Mode->Mode, &cols, &rows); status = conout->QueryMode(conout, conout->Mode->Mode, &cols, &rows);
if (EFI_ERROR(status) || cols * rows == 0) { if (EFI_ERROR(status) || cols * rows == 0) {
cols = 80; cols = TEXT_COLS;
rows = 24; rows = TEXT_ROWS;
} }
/* /*
@ -853,20 +951,74 @@ efi_cons_update_mode(void)
*/ */
mode = parse_uefi_con_out(); mode = parse_uefi_con_out();
if ((mode & (RB_SERIAL | RB_MULTIPLE)) == 0) { if ((mode & (RB_SERIAL | RB_MULTIPLE)) == 0) {
if (buffer != NULL) { conout->EnableCursor(conout, FALSE);
if (tp.tp_row == rows && tp.tp_col == cols) gfx_state.tg_cursor_visible = false;
return (true);
free(buffer); if (gfx_state.tg_fb_type == FB_TEXT) {
gfx_state.tg_functions = &tf;
/* ensure the following are not set for text mode */
unsetenv("screen.height");
unsetenv("screen.width");
unsetenv("screen.depth");
} else { } else {
teken_init(&teken, &tf, NULL); uint32_t fb_height, fb_width;
fb_height = gfx_state.tg_fb.fb_height;
fb_width = gfx_state.tg_fb.fb_width;
/*
* setup_font() can adjust terminal size.
* Note, we assume 80x24 terminal first, this is
* because the font selection will attempt to achieve
* at least this terminal dimension and we do not
* end up with too small font.
*/
gfx_state.tg_tp.tp_row = TEXT_ROWS;
gfx_state.tg_tp.tp_col = TEXT_COLS;
setup_font(&gfx_state, fb_height, fb_width);
rows = gfx_state.tg_tp.tp_row;
cols = gfx_state.tg_tp.tp_col;
/* Point of origin in pixels. */
gfx_state.tg_origin.tp_row = (fb_height -
(rows * gfx_state.tg_font.vf_height)) / 2;
gfx_state.tg_origin.tp_col = (fb_width -
(cols * gfx_state.tg_font.vf_width)) / 2;
/* UEFI gop has depth 32. */
gfx_state.tg_glyph_size = gfx_state.tg_font.vf_height *
gfx_state.tg_font.vf_width * 4;
free(gfx_state.tg_glyph);
gfx_state.tg_glyph = malloc(gfx_state.tg_glyph_size);
if (gfx_state.tg_glyph == NULL)
return (false);
gfx_state.tg_functions = &tfx;
snprintf(env, sizeof (env), "%d", fb_height);
env_setenv("screen.height", EV_VOLATILE | EV_NOHOOK,
env, env_noset, env_screen_nounset);
snprintf(env, sizeof (env), "%d", fb_width);
env_setenv("screen.width", EV_VOLATILE | EV_NOHOOK,
env, env_noset, env_screen_nounset);
snprintf(env, sizeof (env), "%d",
gfx_state.tg_fb.fb_bpp);
env_setenv("screen.depth", EV_VOLATILE | EV_NOHOOK,
env, env_noset, env_screen_nounset);
} }
tp.tp_row = rows; /* Record our terminal screen size. */
tp.tp_col = cols; gfx_state.tg_tp.tp_row = rows;
buffer = malloc(rows * cols * sizeof(*buffer)); gfx_state.tg_tp.tp_col = cols;
if (buffer != NULL) {
teken_set_winsize(&teken, &tp); teken_init(&gfx_state.tg_teken, gfx_state.tg_functions,
a = teken_get_defattr(&teken); &gfx_state);
free(screen_buffer);
screen_buffer = malloc(rows * cols * sizeof(*screen_buffer));
if (screen_buffer != NULL) {
teken_set_winsize(&gfx_state.tg_teken,
&gfx_state.tg_tp);
a = teken_get_defattr(&gfx_state.tg_teken);
attr = *a; attr = *a;
/* /*
@ -880,7 +1032,7 @@ efi_cons_update_mode(void)
ptr = getenv("teken.bg_color"); ptr = getenv("teken.bg_color");
attr.ta_bgcolor = strtol(ptr, NULL, 10); attr.ta_bgcolor = strtol(ptr, NULL, 10);
teken_set_defattr(&teken, &attr); teken_set_defattr(&gfx_state.tg_teken, &attr);
} else { } else {
snprintf(env, sizeof(env), "%d", snprintf(env, sizeof(env), "%d",
attr.ta_fgcolor); attr.ta_fgcolor);
@ -891,18 +1043,12 @@ efi_cons_update_mode(void)
env_setenv("teken.bg_color", EV_VOLATILE, env, env_setenv("teken.bg_color", EV_VOLATILE, env,
efi_set_colors, env_nounset); efi_set_colors, env_nounset);
} }
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
buffer[col + row * tp.tp_col].c = ' ';
buffer[col + row * tp.tp_col].a = attr;
}
}
} }
} }
if (screen_buffer == NULL) {
conout->EnableCursor(conout, TRUE);
#ifdef TERM_EMU #ifdef TERM_EMU
if (buffer == NULL) {
conout->SetAttribute(conout, EFI_TEXT_ATTR(DEFAULT_FGCOLOR, conout->SetAttribute(conout, EFI_TEXT_ATTR(DEFAULT_FGCOLOR,
DEFAULT_BGCOLOR)); DEFAULT_BGCOLOR));
end_term(); end_term();
@ -910,8 +1056,23 @@ efi_cons_update_mode(void)
curs_move(&curx, &cury, curx, cury); curs_move(&curx, &cury, curx, cury);
fg_c = DEFAULT_FGCOLOR; fg_c = DEFAULT_FGCOLOR;
bg_c = DEFAULT_BGCOLOR; bg_c = DEFAULT_BGCOLOR;
}
#endif #endif
} else {
/* Improve visibility */
if (attr.ta_bgcolor == TC_WHITE)
attr.ta_bgcolor |= TC_LIGHT;
teken_set_defattr(&gfx_state.tg_teken, &attr);
/* Draw frame around terminal area. */
cons_draw_frame(&attr);
/*
* Erase display, this will also fill our screen
* buffer.
*/
teken_input(&gfx_state.tg_teken, "\e[2J", 4);
gfx_state.tg_functions->tf_param(&gfx_state,
TP_SHOWCURSOR, 1);
}
snprintf(env, sizeof (env), "%u", (unsigned)rows); snprintf(env, sizeof (env), "%u", (unsigned)rows);
setenv("LINES", env, 1); setenv("LINES", env, 1);
@ -926,8 +1087,13 @@ efi_cons_init(int arg)
{ {
EFI_STATUS status; EFI_STATUS status;
conout->EnableCursor(conout, TRUE); if (efi_started)
if (efi_cons_update_mode()) return (0);
efi_started = true;
gfx_framework_init();
if (cons_update_mode(gfx_state.tg_fb_type != FB_TEXT))
return (0); return (0);
return (1); return (1);
@ -1035,12 +1201,12 @@ efi_cons_putchar(int c)
* Don't use Teken when we're doing pure serial, or a multiple console * Don't use Teken when we're doing pure serial, or a multiple console
* with video "primary" because that's also serial. * with video "primary" because that's also serial.
*/ */
if ((mode & (RB_SERIAL | RB_MULTIPLE)) != 0 || buffer == NULL) { if ((mode & (RB_SERIAL | RB_MULTIPLE)) != 0 || screen_buffer == NULL) {
input_byte(ch); input_byte(ch);
return; return;
} }
teken_input(&teken, &ch, sizeof (ch)); teken_input(&gfx_state.tg_teken, &ch, sizeof (ch));
} }
static int static int

View File

@ -22,7 +22,9 @@ SRCS= autoload.c \
framebuffer.c \ framebuffer.c \
main.c \ main.c \
self_reloc.c \ self_reloc.c \
vers.c vers.c \
gfx_fb.c \
8x16.c
CFLAGS+= -I${.CURDIR}/../loader CFLAGS+= -I${.CURDIR}/../loader
.if ${MK_LOADER_ZFS} != "no" .if ${MK_LOADER_ZFS} != "no"
@ -33,6 +35,11 @@ CFLAGS+= -DEFI_ZFS_BOOT
HAVE_ZFS= yes HAVE_ZFS= yes
.endif .endif
CFLAGS.gfx_fb.c += -I$(SRCTOP)/sys/teken
CFLAGS.gfx_fb.c += -I${SRCTOP}/sys/cddl/contrib/opensolaris/common/lz4
CFLAGS.gfx_fb.c += -I${SRCTOP}/contrib/pnglite
CFLAGS.gfx_fb.c += -DHAVE_MEMCPY -I${SRCTOP}/sys/contrib/zlib
# We implement a slightly non-standard %S in that it always takes a # We implement a slightly non-standard %S in that it always takes a
# CHAR16 that's common in UEFI-land instead of a wchar_t. This only # CHAR16 that's common in UEFI-land instead of a wchar_t. This only
# seems to matter on arm64 where wchar_t defaults to an int instead # seems to matter on arm64 where wchar_t defaults to an int instead
@ -74,6 +81,11 @@ VERSION_FILE= ${.CURDIR}/../loader/version
# Always add MI sources # Always add MI sources
.include "${BOOTSRC}/loader.mk" .include "${BOOTSRC}/loader.mk"
CLEANFILES+= 8x16.c
8x16.c: ${SRCTOP}/contrib/terminus/ter-u16v.bdf
vtfontcvt -f compressed-source -o ${.TARGET} ${.ALLSRC}
FILES+= ${LOADER}.efi FILES+= ${LOADER}.efi
FILESMODE_${LOADER}.efi= ${BINMODE} FILESMODE_${LOADER}.efi= ${BINMODE}

View File

@ -447,7 +447,7 @@ bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp)
*/ */
uint32_t mdt[] = { uint32_t mdt[] = {
MODINFOMD_SSYM, MODINFOMD_ESYM, MODINFOMD_KERNEND, MODINFOMD_SSYM, MODINFOMD_ESYM, MODINFOMD_KERNEND,
MODINFOMD_ENVP, MODINFOMD_ENVP, MODINFOMD_FONT,
#if defined(LOADER_FDT_SUPPORT) #if defined(LOADER_FDT_SUPPORT)
MODINFOMD_DTBP MODINFOMD_DTBP
#endif #endif
@ -480,6 +480,11 @@ bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp)
/* Pad to a page boundary. */ /* Pad to a page boundary. */
addr = roundup(addr, PAGE_SIZE); addr = roundup(addr, PAGE_SIZE);
addr = build_font_module(addr);
/* Pad to a page boundary. */
addr = roundup(addr, PAGE_SIZE);
/* Copy our environment. */ /* Copy our environment. */
envp = addr; envp = addr;
addr = bi_copyenv(addr); addr = bi_copyenv(addr);
@ -503,17 +508,17 @@ bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp)
if (kfp == NULL) if (kfp == NULL)
panic("can't find kernel file"); panic("can't find kernel file");
kernend = 0; /* fill it in later */ kernend = 0; /* fill it in later */
file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof(howto), &howto);
file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); file_addmetadata(kfp, MODINFOMD_ENVP, sizeof(envp), &envp);
#if defined(LOADER_FDT_SUPPORT) #if defined(LOADER_FDT_SUPPORT)
if (dtb_size) if (dtb_size)
file_addmetadata(kfp, MODINFOMD_DTBP, sizeof dtbp, &dtbp); file_addmetadata(kfp, MODINFOMD_DTBP, sizeof(dtbp), &dtbp);
else else
printf("WARNING! Trying to fire up the kernel, but no " printf("WARNING! Trying to fire up the kernel, but no "
"device tree blob found!\n"); "device tree blob found!\n");
#endif #endif
file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof(kernend), &kernend);
file_addmetadata(kfp, MODINFOMD_FW_HANDLE, sizeof ST, &ST); file_addmetadata(kfp, MODINFOMD_FW_HANDLE, sizeof(ST), &ST);
#ifdef LOADER_GELI_SUPPORT #ifdef LOADER_GELI_SUPPORT
geli_export_key_metadata(kfp); geli_export_key_metadata(kfp);
#endif #endif

View File

@ -40,9 +40,10 @@ __FBSDID("$FreeBSD$");
#include <efipciio.h> #include <efipciio.h>
#include <machine/metadata.h> #include <machine/metadata.h>
#include "bootstrap.h"
#include "framebuffer.h" #include "framebuffer.h"
static EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
static EFI_GUID pciio_guid = EFI_PCI_IO_PROTOCOL_GUID; static EFI_GUID pciio_guid = EFI_PCI_IO_PROTOCOL_GUID;
static EFI_GUID uga_guid = EFI_UGA_DRAW_PROTOCOL_GUID; static EFI_GUID uga_guid = EFI_UGA_DRAW_PROTOCOL_GUID;
@ -586,7 +587,7 @@ gop_autoresize(EFI_GRAPHICS_OUTPUT *gop)
mode, EFI_ERROR_CODE(status)); mode, EFI_ERROR_CODE(status));
return (CMD_ERROR); return (CMD_ERROR);
} }
(void) efi_cons_update_mode(); (void) cons_update_mode(true);
} }
return (CMD_OK); return (CMD_OK);
} }
@ -611,7 +612,7 @@ text_autoresize()
} }
if (max_dim > 0) if (max_dim > 0)
conout->SetMode(conout, best_mode); conout->SetMode(conout, best_mode);
(void) efi_cons_update_mode(); (void) cons_update_mode(true);
return (CMD_OK); return (CMD_OK);
} }
@ -699,8 +700,10 @@ command_gop(int argc, char *argv[])
argv[0], mode, EFI_ERROR_CODE(status)); argv[0], mode, EFI_ERROR_CODE(status));
return (CMD_ERROR); return (CMD_ERROR);
} }
(void) efi_cons_update_mode(); (void) cons_update_mode(true);
} else if (!strcmp(argv[1], "get")) { } else if (strcmp(argv[1], "off") == 0) {
(void) cons_update_mode(false);
} else if (strcmp(argv[1], "get") == 0) {
if (argc != 2) if (argc != 2)
goto usage; goto usage;
efifb_from_gop(&efifb, gop->Mode, gop->Mode->Info); efifb_from_gop(&efifb, gop->Mode, gop->Mode->Info);
@ -728,7 +731,7 @@ command_gop(int argc, char *argv[])
usage: usage:
snprintf(command_errbuf, sizeof(command_errbuf), snprintf(command_errbuf, sizeof(command_errbuf),
"usage: %s [list | get | set <mode>]", argv[0]); "usage: %s [list | get | set <mode> | off]", argv[0]);
return (CMD_ERROR); return (CMD_ERROR);
} }

View File

@ -1155,6 +1155,7 @@ main(int argc, CHAR16 *argv[])
!interactive_interrupt("Failed to find bootable partition")) !interactive_interrupt("Failed to find bootable partition"))
return (EFI_NOT_FOUND); return (EFI_NOT_FOUND);
autoload_font(false); /* Set up the font list for console. */
efi_init_environment(); efi_init_environment();
#if !defined(__arm__) #if !defined(__arm__)
@ -1354,7 +1355,7 @@ command_mode(int argc, char *argv[])
printf("couldn't set mode %d\n", mode); printf("couldn't set mode %d\n", mode);
return (CMD_ERROR); return (CMD_ERROR);
} }
(void) efi_cons_update_mode(); (void) cons_update_mode(true);
return (CMD_OK); return (CMD_OK);
} }

View File

@ -15,7 +15,7 @@ CFLAGS+= -fPIC
.endif .endif
CFLAGS+= -I${FICLSRC} -I${FICLSRC}/${FICL_CPUARCH} -I${LDRSRC} CFLAGS+= -I${FICLSRC} -I${FICLSRC}/${FICL_CPUARCH} -I${LDRSRC}
CFLAGS+= -DBF_DICTSIZE=15000 CFLAGS+= -DBF_DICTSIZE=30000
.if ${MK_LOADER_VERIEXEC} != "no" .if ${MK_LOADER_VERIEXEC} != "no"
CFLAGS+= -DLOADER_VERIEXEC -I${SRCTOP}/lib/libsecureboot/h CFLAGS+= -DLOADER_VERIEXEC -I${SRCTOP}/lib/libsecureboot/h

View File

@ -12,6 +12,8 @@ BASE_SRCS= dict.c ficl.c fileaccess.c float.c loader.c math64.c \
SRCS= ${BASE_SRCS} sysdep.c softcore.c SRCS= ${BASE_SRCS} sysdep.c softcore.c
CLEANFILES+= softcore.c testmain testmain.o CLEANFILES+= softcore.c testmain testmain.o
CFLAGS.loader.c += -I${SRCTOP}/sys/teken
CFLAGS.loader.c += -I${SRCTOP}/contrib/pnglite
.ifmake testmain .ifmake testmain
CFLAGS= -DTESTMAIN -D_TESTMAIN CFLAGS= -DTESTMAIN -D_TESTMAIN
CFLAGS+= -I${FICLSRC} -I${FICLSRC}/${FICL_CPUARCH} -I${LDRSRC} CFLAGS+= -I${FICLSRC} -I${FICLSRC}/${FICL_CPUARCH} -I${LDRSRC}

View File

@ -46,6 +46,8 @@
#include "bootstrap.h" #include "bootstrap.h"
#include <string.h> #include <string.h>
#include <uuid.h> #include <uuid.h>
#include <gfx_fb.h>
#include <pnglite.h>
#include "ficl.h" #include "ficl.h"
/* FreeBSD's loader interaction words and extras /* FreeBSD's loader interaction words and extras
@ -65,6 +67,182 @@
* .# ( value -- ) * .# ( value -- )
*/ */
#ifndef TESTMAIN
/* ( flags x1 y1 x2 y2 -- flag ) */
void
ficl_term_putimage(FICL_VM *pVM)
{
char *namep, *name;
int names;
unsigned long ret = FICL_FALSE;
uint32_t x1, y1, x2, y2, f;
png_t png;
int error;
#if FICL_ROBUST > 1
vmCheckStack(pVM, 7, 1);
#endif
names = stackPopINT(pVM->pStack);
namep = (char *) stackPopPtr(pVM->pStack);
y2 = stackPopINT(pVM->pStack);
x2 = stackPopINT(pVM->pStack);
y1 = stackPopINT(pVM->pStack);
x1 = stackPopINT(pVM->pStack);
f = stackPopINT(pVM->pStack);
x1 = gfx_state.tg_origin.tp_col + x1 * gfx_state.tg_font.vf_width;
y1 = gfx_state.tg_origin.tp_row + y1 * gfx_state.tg_font.vf_height;
if (x2 != 0) {
x2 = gfx_state.tg_origin.tp_col +
x2 * gfx_state.tg_font.vf_width;
}
if (y2 != 0) {
y2 = gfx_state.tg_origin.tp_row +
y2 * gfx_state.tg_font.vf_height;
}
name = ficlMalloc(names + 1);
if (!name)
vmThrowErr(pVM, "Error: out of memory");
(void) strncpy(name, namep, names);
name[names] = '\0';
if ((error = png_open(&png, name)) != PNG_NO_ERROR) {
if (f & FL_PUTIMAGE_DEBUG)
printf("%s\n", png_error_string(error));
} else {
if (gfx_fb_putimage(&png, x1, y1, x2, y2, f) == 0)
ret = FICL_TRUE; /* success */
(void) png_close(&png);
}
ficlFree(name);
stackPushUNS(pVM->pStack, ret);
}
/* ( flags x1 y1 x2 y2 -- flag ) */
void
ficl_fb_putimage(FICL_VM *pVM)
{
char *namep, *name;
int names;
unsigned long ret = FICL_FALSE;
uint32_t x1, y1, x2, y2, f;
png_t png;
int error;
#if FICL_ROBUST > 1
vmCheckStack(pVM, 7, 1);
#endif
names = stackPopINT(pVM->pStack);
namep = (char *) stackPopPtr(pVM->pStack);
y2 = stackPopINT(pVM->pStack);
x2 = stackPopINT(pVM->pStack);
y1 = stackPopINT(pVM->pStack);
x1 = stackPopINT(pVM->pStack);
f = stackPopINT(pVM->pStack);
name = ficlMalloc(names + 1);
if (!name)
vmThrowErr(pVM, "Error: out of memory");
(void) strncpy(name, namep, names);
name[names] = '\0';
if ((error = png_open(&png, name)) != PNG_NO_ERROR) {
if (f & FL_PUTIMAGE_DEBUG)
printf("%s\n", png_error_string(error));
} else {
if (gfx_fb_putimage(&png, x1, y1, x2, y2, f) == 0)
ret = FICL_TRUE; /* success */
(void) png_close(&png);
}
ficlFree(name);
stackPushUNS(pVM->pStack, ret);
}
void
ficl_fb_setpixel(FICL_VM *pVM)
{
FICL_UNS x, y;
#if FICL_ROBUST > 1
vmCheckStack(pVM, 2, 0);
#endif
y = stackPopUNS(pVM->pStack);
x = stackPopUNS(pVM->pStack);
gfx_fb_setpixel(x, y);
}
void
ficl_fb_line(FICL_VM *pVM)
{
FICL_UNS x0, y0, x1, y1, wd;
#if FICL_ROBUST > 1
vmCheckStack(pVM, 5, 0);
#endif
wd = stackPopUNS(pVM->pStack);
y1 = stackPopUNS(pVM->pStack);
x1 = stackPopUNS(pVM->pStack);
y0 = stackPopUNS(pVM->pStack);
x0 = stackPopUNS(pVM->pStack);
gfx_fb_line(x0, y0, x1, y1, wd);
}
void
ficl_fb_bezier(FICL_VM *pVM)
{
FICL_UNS x0, y0, x1, y1, x2, y2, width;
#if FICL_ROBUST > 1
vmCheckStack(pVM, 7, 0);
#endif
width = stackPopUNS(pVM->pStack);
y2 = stackPopUNS(pVM->pStack);
x2 = stackPopUNS(pVM->pStack);
y1 = stackPopUNS(pVM->pStack);
x1 = stackPopUNS(pVM->pStack);
y0 = stackPopUNS(pVM->pStack);
x0 = stackPopUNS(pVM->pStack);
gfx_fb_bezier(x0, y0, x1, y1, x2, y2, width);
}
void
ficl_fb_drawrect(FICL_VM *pVM)
{
FICL_UNS x1, x2, y1, y2, fill;
#if FICL_ROBUST > 1
vmCheckStack(pVM, 5, 0);
#endif
fill = stackPopUNS(pVM->pStack);
y2 = stackPopUNS(pVM->pStack);
x2 = stackPopUNS(pVM->pStack);
y1 = stackPopUNS(pVM->pStack);
x1 = stackPopUNS(pVM->pStack);
gfx_fb_drawrect(x1, y1, x2, y2, fill);
}
void
ficl_term_drawrect(FICL_VM *pVM)
{
FICL_UNS x1, x2, y1, y2;
#if FICL_ROBUST > 1
vmCheckStack(pVM, 4, 0);
#endif
y2 = stackPopUNS(pVM->pStack);
x2 = stackPopUNS(pVM->pStack);
y1 = stackPopUNS(pVM->pStack);
x1 = stackPopUNS(pVM->pStack);
gfx_term_drawrect(x1, y1, x2, y2);
}
#endif /* TESTMAIN */
void void
ficlSetenv(FICL_VM *pVM) ficlSetenv(FICL_VM *pVM)
{ {
@ -867,6 +1045,13 @@ void ficlCompilePlatform(FICL_SYSTEM *pSys)
dictAppendWord(dp, "uuid-from-string", ficlUuidFromString, FW_DEFAULT); dictAppendWord(dp, "uuid-from-string", ficlUuidFromString, FW_DEFAULT);
dictAppendWord(dp, "uuid-to-string", ficlUuidToString, FW_DEFAULT); dictAppendWord(dp, "uuid-to-string", ficlUuidToString, FW_DEFAULT);
#ifndef TESTMAIN #ifndef TESTMAIN
dictAppendWord(dp, "fb-setpixel", ficl_fb_setpixel, FW_DEFAULT);
dictAppendWord(dp, "fb-line", ficl_fb_line, FW_DEFAULT);
dictAppendWord(dp, "fb-bezier", ficl_fb_bezier, FW_DEFAULT);
dictAppendWord(dp, "fb-drawrect", ficl_fb_drawrect, FW_DEFAULT);
dictAppendWord(dp, "fb-putimage", ficl_fb_putimage, FW_DEFAULT);
dictAppendWord(dp, "term-drawrect", ficl_term_drawrect, FW_DEFAULT);
dictAppendWord(dp, "term-putimage", ficl_term_putimage, FW_DEFAULT);
dictAppendWord(dp, "isvirtualized?",ficlIsvirtualizedQ, FW_DEFAULT); dictAppendWord(dp, "isvirtualized?",ficlIsvirtualizedQ, FW_DEFAULT);
#endif #endif

66
stand/fonts/INDEX.fonts Normal file
View File

@ -0,0 +1,66 @@
#
# $FreeBSD$
#
# database for vidfont(8)
#
# Format <file>:<lang>:<description>
#
# lang: ar bg cs da de el en es fi fr hr hu hy is it iw ja ko nl no pl
# pt ro ru sh sk sl sv tr uk zh
# lang: lang,lang
#
# Example:
# terminus-b32.fnt:de:Terminus Schriftart
# terminus-b32.fnt:en:Terminus font
#
# If lang is empty use 'en' (us-english) as default.
#
# See also setlocale(3),
# /usr/share/locale, /usr/X11/lib/X11/locale/locale.alias
#
################################
# Language support: MENU, FONT
#
MENU:en:Choose your terminal font
MENU:da:Vælg skrifttypen til din terminal
MENU:de:Wählen Sie Ihre Schrift
MENU:fr:Choisissez votre fonte écran
#
# The font definition for "en" is the fall-back font for
# all languages.
# Add language specific font definitions only where required!
#
FONT:en:8x16v.fnt
#
6x12.fnt:en:Terminus BSD Console, size 12
6x12.fnt:da:Terminus BSD-konsol, størrelse 12
6x12.fnt:de:Terminus BSD Console, Größe 12
8x14.fnt:en:Terminus BSD Console, size 14
8x14.fnt:da:Terminus BSD-konsol, størrelse 14
8x14.fnt:de:Terminus BSD Console, Größe 14
8x16.fnt:en:Terminus BSD Console, size 16
8x16.fnt:da:Terminus BSD-konsol, størrelse 16
8x16.fnt:de:Terminus BSD Console, Größe 16
10x18.fnt:en:Terminus BSD Console, size 18
10x18.fnt:da:Terminus BSD-konsol, størrelse 18
10x18.fnt:de:Terminus BSD Console, Größe 18
10x20.fnt:en:Terminus BSD Console, size 20
10x20.fnt:da:Terminus BSD-konsol, størrelse 20
10x20.fnt:de:Terminus BSD Console, Größe 20
11x22.fnt:en:Terminus BSD Console, size 22
11x22.fnt:da:Terminus BSD-konsol, størrelse 22
11x22.fnt:de:Terminus BSD Console, Größe 22
12x24.fnt:en:Terminus BSD Console, size 24
12x24.fnt:da:Terminus BSD-konsol, størrelse 24
12x24.fnt:de:Terminus BSD Console, Größe 24
14x28.fnt:en:Terminus BSD Console, size 28
14x28.fnt:da:Terminus BSD-konsol, størrelse 28
14x28.fnt:de:Terminus BSD Console, Größe 28
16x32.fnt:en:Terminus BSD Console, size 32
16x32.fnt:da:Terminus BSD-konsol, størrelse 32
16x32.fnt:de:Terminus BSD Console, Größe 32
# (fset 'langnew
# "\M-}\C-p\C-k\C-y\C-m\C-y\M-}")

81
stand/fonts/Makefile Normal file
View File

@ -0,0 +1,81 @@
# $FreeBSD$
.include <bsd.init.mk>
.PATH: ${SRCTOP}/contrib/terminus
FONTS= \
6x12.fnt.gz \
8x14.fnt.gz \
8x14v.fnt.gz \
8x16.fnt.gz \
8x16v.fnt.gz \
10x18.fnt.gz \
10x20.fnt.gz \
11x22.fnt.gz \
12x24.fnt.gz \
14x28.fnt.gz \
16x32.fnt.gz \
FILES= ${FONTS} INDEX.fonts
FILESDIR= /boot/fonts
CLEANFILES+= ${FONTS} ${FONTS:T:S/${COMPRESS_EXT}//g}
6x12.fnt.gz: 6x12.fnt
${COMPRESS_CMD} ${.ALLSRC} > ${.TARGET}
8x14.fnt.gz: 8x14.fnt
${COMPRESS_CMD} ${.ALLSRC} > ${.TARGET}
8x14v.fnt.gz: 8x14v.fnt
${COMPRESS_CMD} ${.ALLSRC} > ${.TARGET}
8x16.fnt.gz: 8x16.fnt
${COMPRESS_CMD} ${.ALLSRC} > ${.TARGET}
8x16v.fnt.gz: 8x16v.fnt
${COMPRESS_CMD} ${.ALLSRC} > ${.TARGET}
10x18.fnt.gz: 10x18.fnt
${COMPRESS_CMD} ${.ALLSRC} > ${.TARGET}
10x20.fnt.gz: 10x20.fnt
${COMPRESS_CMD} ${.ALLSRC} > ${.TARGET}
11x22.fnt.gz: 11x22.fnt
${COMPRESS_CMD} ${.ALLSRC} > ${.TARGET}
12x24.fnt.gz: 12x24.fnt
${COMPRESS_CMD} ${.ALLSRC} > ${.TARGET}
14x28.fnt.gz: 14x28.fnt
${COMPRESS_CMD} ${.ALLSRC} > ${.TARGET}
16x32.fnt.gz: 16x32.fnt
${COMPRESS_CMD} ${.ALLSRC} > ${.TARGET}
6x12.fnt: ter-u12n.bdf ter-u12b.bdf
vtfontcvt -o ${.TARGET} ${.ALLSRC}
8x14.fnt: ter-u14n.bdf ter-u14b.bdf
vtfontcvt -o ${.TARGET} ${.ALLSRC}
8x14v.fnt: ter-u14v.bdf
vtfontcvt -o ${.TARGET} ${.ALLSRC}
8x16.fnt: ter-u16n.bdf ter-u16b.bdf
vtfontcvt -o ${.TARGET} ${.ALLSRC}
8x16v.fnt: ter-u16v.bdf
vtfontcvt -o ${.TARGET} ${.ALLSRC}
10x18.fnt: ter-u18n.bdf ter-u18b.bdf
vtfontcvt -o ${.TARGET} ${.ALLSRC}
10x20.fnt: ter-u20n.bdf ter-u20b.bdf
vtfontcvt -o ${.TARGET} ${.ALLSRC}
11x22.fnt: ter-u22n.bdf ter-u22b.bdf
vtfontcvt -o ${.TARGET} ${.ALLSRC}
12x24.fnt: ter-u24n.bdf ter-u24b.bdf
vtfontcvt -o ${.TARGET} ${.ALLSRC}
14x28.fnt: ter-u28n.bdf ter-u28b.bdf
vtfontcvt -o ${.TARGET} ${.ALLSRC}
16x32.fnt: ter-u32n.bdf ter-u32b.bdf
vtfontcvt -o ${.TARGET} ${.ALLSRC}
.include <bsd.prog.mk>

View File

@ -82,6 +82,10 @@ variable logoY
then then
; ;
: draw-beastie
['] draw-beastie console-iterate
;
also support-functions also support-functions
: beastie-start ( -- ) \ starts the menu : beastie-start ( -- ) \ starts the menu

View File

@ -34,6 +34,18 @@
: brand ( x y -- ) \ "FreeBSD" [wide] logo in B/W (7 rows x 42 columns) : brand ( x y -- ) \ "FreeBSD" [wide] logo in B/W (7 rows x 42 columns)
framebuffer? if
s" term-putimage" sfind if
\ note, we use 0, 0 for image upper left as origin,
\ and 0, 7 for lower right to preserve aspect ratio
>r 0 0 0 0 7
s" /boot/images/freebsd-brand-rev.png"
r> execute if 2drop exit then
else
drop
then
then
s" ______ ____ _____ _____ " brand+ s" ______ ____ _____ _____ " brand+
s" | ____| | _ \ / ____| __ \ " brand+ s" | ____| | _ \ / ____| __ \ " brand+
s" | |___ _ __ ___ ___ | |_) | (___ | | | |" brand+ s" | |___ _ __ ___ ___ | |_) | (___ | | | |" brand+

View File

@ -72,3 +72,7 @@ variable brandY
else drop then else drop then
then then
; ;
: draw-brand
['] draw-brand console-iterate
;

View File

@ -28,7 +28,7 @@ marker task-color.4th
\ This function returns FALSE if the `loader_color' environment variable is set \ This function returns FALSE if the `loader_color' environment variable is set
\ to NO, no, or 0. It returns TRUE if `loader_color' is set to any other value. \ to NO, no, or 0. It returns TRUE if `loader_color' is set to any other value.
\ If `loader_color' is unset, TRUE is returned (unless booting serial). \ If `loader_color' is unset, TRUE is returned.
\ \
: loader_color? ( -- t ) : loader_color? ( -- t )
@ -44,12 +44,8 @@ marker task-color.4th
FALSE exit FALSE exit
then then
drop drop
then
drop
\ It is enabled. \ It is enabled.
TRUE TRUE
else
\ `loader_color' is unset.
\ Default to using color unless serial boot is active.
drop
boot_serial? 0=
then
; ;

View File

@ -121,6 +121,20 @@ only forth definitions also frame-drawing
; ;
: box ( w h x y -- ) \ Draw a box : box ( w h x y -- ) \ Draw a box
framebuffer? if
s" term-drawrect" sfind if
>R
rot ( w x y h )
over + >R ( w x y -- R: y+h )
swap rot ( y x w -- R: y+h )
over + >R ( y x -- R: y+h x+w )
swap R> R> R> execute
exit
else
drop
then
then
\ Non-framebuffer version
2dup 1+ 4 pick 1- -rot 2dup 1+ 4 pick 1- -rot
vline \ Draw left vert line vline \ Draw left vert line
2dup 1+ swap 5 pick + swap 4 pick 1- -rot 2dup 1+ swap 5 pick + swap 4 pick 1- -rot

View File

@ -35,6 +35,18 @@
: logo ( x y -- ) \ color Orb mascot (15 rows x 30 columns) : logo ( x y -- ) \ color Orb mascot (15 rows x 30 columns)
framebuffer? if
s" term-putimage" sfind if
>r 2dup ( x y x y )
>r 0 swap r> ( x y 0 x y )
dup 0 swap 15 + ( x y 0 x y 0 y+15 )
s" /boot/images/freebsd-logo-rev.png"
r> execute if 2drop exit then
else
drop
then
then
s" @[31m``` @[31;1m`@[31m" logo+ s" @[31m``` @[31;1m`@[31m" logo+
s" s` `.....---...@[31;1m....--.``` -/@[31m" logo+ s" s` `.....---...@[31;1m....--.``` -/@[31m" logo+
s" +o .--` @[31;1m/y:` +.@[31m" logo+ s" +o .--` @[31;1m/y:` +.@[31m" logo+

View File

@ -991,6 +991,24 @@ only forth definitions also menu-infrastructure
menu-create menu-create
; ;
: menu-box
f_double ( default frame type )
\ Interpret a custom frame type for the menu
TRUE ( draw a box? default yes, but might be altered below )
s" loader_menu_frame" getenv dup -1 = if ( 1 )
drop \ no custom frame type
else ( 1 ) 2dup s" single" compare-insensitive 0= if ( 2 )
f_single ( see frames.4th )
else ( 2 ) 2dup s" double" compare-insensitive 0= if ( 3 )
f_double ( see frames.4th )
else ( 3 ) s" none" compare-insensitive 0= if ( 4 )
drop FALSE \ don't draw a box
( 4 ) then ( 3 ) then ( 2 ) then ( 1 ) then
if
42 13 menuX @ 3 - menuY @ 1- box \ Draw frame (w,h,x,y)
then
;
\ This function initializes the menu. Call this from your `loader.rc' file \ This function initializes the menu. Call this from your `loader.rc' file
\ before calling any other menu-related functions. \ before calling any other menu-related functions.
\ \
@ -1021,21 +1039,7 @@ only forth definitions also menu-infrastructure
then then
menuX ! menuX !
\ Interpret a custom frame type for the menu ['] menu-box console-iterate
TRUE ( draw a box? default yes, but might be altered below )
s" loader_menu_frame" getenv dup -1 = if ( 1 )
drop \ no custom frame type
else ( 1 ) 2dup s" single" compare-insensitive 0= if ( 2 )
f_single ( see frames.4th )
else ( 2 ) 2dup s" double" compare-insensitive 0= if ( 3 )
f_double ( see frames.4th )
else ( 3 ) s" none" compare-insensitive 0= if ( 4 )
drop FALSE \ don't draw a box
( 4 ) then ( 3 ) then ( 2 ) then ( 1 ) then
if
42 13 menuX @ 3 - menuY @ 1- box \ Draw frame (w,h,x,y)
then
0 25 at-xy \ Move cursor to the bottom for output 0 25 at-xy \ Move cursor to the bottom for output
; ;

View File

@ -190,6 +190,25 @@ create last_module_option sizeof module.next allot 0 last_module_option !
0 0 0 0
; ;
: strspn { addr len addr1 len1 | paddr plen -- addr' len' }
begin
len
while
addr1 to paddr
len1 to plen
begin
plen
while
addr c@ paddr c@ = if addr len exit then
paddr 1+ to paddr
plen 1- to plen
repeat
addr 1 + to addr
len 1 - to len
repeat
0 0
;
: s' \ same as s", allows " in the string : s' \ same as s", allows " in the string
[char] ' parse [char] ' parse
state @ if postpone sliteral then state @ if postpone sliteral then
@ -201,6 +220,53 @@ create last_module_option sizeof module.next allot 0 last_module_option !
: getenv? getenv -1 = if false else drop true then ; : getenv? getenv -1 = if false else drop true then ;
\ execute xt for each device listed in console variable.
\ this allows us to have device specific output for logos, menu frames etc
: console-iterate { xt | caddr clen taddr tlen -- }
\ get current console and save it
s" console" getenv
['] strdup catch if 2drop exit then
to clen to caddr
clen to tlen
caddr to taddr
begin
tlen
while
taddr tlen s" , " strspn
\ we need to handle 3 cases for addr len pairs on stack:
\ addr len are 0 0 - there was no comma nor space
\ addr len are x 0 - the first char is either comma or space
\ addr len are x y.
2dup + 0= if
\ there was no comma nor space.
2drop
taddr tlen s" console" setenv
xt execute
0 to tlen
else dup 0= if
2drop
else
dup ( taddr' tlen' tlen' )
tlen swap - dup
0= if \ sequence of comma and space?
drop
else
taddr swap s" console" setenv
xt execute
then
to tlen
to taddr
then then
tlen 0> if \ step over separator
tlen 1- to tlen
taddr 1+ to taddr
then
repeat
caddr clen s" console" setenv \ restore console setup
caddr free drop
;
\ determine if a word appears in a string, case-insensitive \ determine if a word appears in a string, case-insensitive
: contains? ( addr1 len1 addr2 len2 -- 0 | -1 ) : contains? ( addr1 len1 addr2 len2 -- 0 | -1 )
2 pick 0= if 2drop 2drop true exit then 2 pick 0= if 2drop 2drop true exit then
@ -231,14 +297,23 @@ create last_module_option sizeof module.next allot 0 last_module_option !
s" console" getenv dup -1 <> if s" console" getenv dup -1 <> if
s" comconsole" 2swap contains? s" comconsole" 2swap contains?
else drop false then else drop false then
s" boot_serial" getenv dup -1 <> if \ s" boot_serial" getenv dup -1 <> if
swap drop 0> \ swap drop 0>
else drop false then \ else drop false then
or \ console contains comconsole ( or ) boot_serial \ or \ console contains comconsole ( or ) boot_serial
s" boot_multicons" getenv dup -1 <> if \ s" boot_multicons" getenv dup -1 <> if
swap drop 0> \ swap drop 0>
else drop false then \ else drop false then
or \ previous boolean ( or ) boot_multicons \ or \ previous boolean ( or ) boot_multicons
;
: framebuffer? ( -- t )
s" console" getenv
2dup s" efi" compare 0<> >r
s" vidconsole" compare 0<> r> and if
FALSE exit
then
s" screen.depth" getenv?
; ;
\ Private definitions \ Private definitions

View File

@ -9,7 +9,7 @@ SRCS= bio.c biosacpi.c biosdisk.c biosmem.c biospnp.c \
comconsole.c devicename.c elf32_freebsd.c \ comconsole.c devicename.c elf32_freebsd.c \
elf64_freebsd.c multiboot.c multiboot_tramp.S relocater_tramp.S \ elf64_freebsd.c multiboot.c multiboot_tramp.S relocater_tramp.S \
i386_copy.c i386_module.c nullconsole.c pxe.c pxetramp.S \ i386_copy.c i386_module.c nullconsole.c pxe.c pxetramp.S \
time.c vidconsole.c amd64_tramp.S spinconsole.c time.c vidconsole.c vbe.c amd64_tramp.S spinconsole.c
.PATH: ${ZFSSRC} .PATH: ${ZFSSRC}
SRCS+= devicename_stubs.c SRCS+= devicename_stubs.c
CFLAGS+= -I${ZFSSRC} CFLAGS+= -I${ZFSSRC}
@ -29,8 +29,13 @@ CFLAGS+= -DDISK_DEBUG
.endif .endif
# terminal emulation # terminal emulation
CFLAGS.vidconsole.c+= -I${SRCTOP}/sys/teken .if ${BOOT_FRAMEBUFFER_MODE:Uno} == "yes"
CFLAGS.vidconsole.c+= -DFRAMEBUFFER_MODE
.endif
CFLAGS.vidconsole.c+= -I${SRCTOP}/sys/teken -I${SRCTOP}/contrib/pnglite
CFLAGS.teken.c+= -I${SRCTOP}/sys/teken CFLAGS.teken.c+= -I${SRCTOP}/sys/teken
CFLAGS.bootinfo.c+= -I${SRCTOP}/sys/teken -I${SRCTOP}/contrib/pnglite
CFLAGS.vbe.c+= -I${SRCTOP}/sys/teken -I${SRCTOP}/contrib/pnglite
# XXX: make alloca() useable # XXX: make alloca() useable
CFLAGS+= -Dalloca=__builtin_alloca CFLAGS+= -Dalloca=__builtin_alloca

View File

@ -32,10 +32,21 @@ __FBSDID("$FreeBSD$");
#include <sys/reboot.h> #include <sys/reboot.h>
#include <sys/boot.h> #include <sys/boot.h>
#include <sys/linker.h> #include <sys/linker.h>
#include <gfx_fb.h>
#include "bootstrap.h" #include "bootstrap.h"
#include "libi386.h" #include "libi386.h"
#include "vbe.h"
#include "btxv86.h" #include "btxv86.h"
void
bi_load_vbe_data(struct preloaded_file *kfp)
{
if (vbe_available()) {
file_addmetadata(kfp, MODINFOMD_VBE_FB,
sizeof(gfx_state.tg_fb), &gfx_state.tg_fb);
}
}
int int
bi_getboothowto(char *kargs) bi_getboothowto(char *kargs)
{ {

View File

@ -205,6 +205,8 @@ bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t
/* pad to a page boundary */ /* pad to a page boundary */
addr = roundup(addr, PAGE_SIZE); addr = roundup(addr, PAGE_SIZE);
addr = build_font_module(addr);
/* copy our environment */ /* copy our environment */
envp = addr; envp = addr;
addr = bi_copyenv(addr); addr = bi_copyenv(addr);
@ -225,6 +227,7 @@ bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t
#ifdef LOADER_GELI_SUPPORT #ifdef LOADER_GELI_SUPPORT
geli_export_key_metadata(kfp); geli_export_key_metadata(kfp);
#endif #endif
bi_load_vbe_data(kfp);
/* Figure out the size and location of the metadata */ /* Figure out the size and location of the metadata */
*modulep = addr; *modulep = addr;

View File

@ -227,6 +227,8 @@ bi_load64(char *args, vm_offset_t addr, vm_offset_t *modulep,
/* pad to a page boundary */ /* pad to a page boundary */
addr = roundup(addr, PAGE_SIZE); addr = roundup(addr, PAGE_SIZE);
addr = build_font_module(addr);
/* place the metadata before anything */ /* place the metadata before anything */
module = *modulep = addr; module = *modulep = addr;
@ -245,6 +247,7 @@ bi_load64(char *args, vm_offset_t addr, vm_offset_t *modulep,
#ifdef LOADER_GELI_SUPPORT #ifdef LOADER_GELI_SUPPORT
geli_export_key_metadata(kfp); geli_export_key_metadata(kfp);
#endif #endif
bi_load_vbe_data(kfp);
size = bi_copymodules64(0); size = bi_copymodules64(0);

View File

@ -145,6 +145,7 @@ void biosacpi_detect(void);
int i386_autoload(void); int i386_autoload(void);
void bi_load_vbe_data(struct preloaded_file *kfp);
int bi_getboothowto(char *kargs); int bi_getboothowto(char *kargs);
void bi_setboothowto(int howto); void bi_setboothowto(int howto);
vm_offset_t bi_copyenv(vm_offset_t addr); vm_offset_t bi_copyenv(vm_offset_t addr);

1226
stand/i386/libi386/vbe.c Normal file

File diff suppressed because it is too large Load Diff

163
stand/i386/libi386/vbe.h Normal file
View File

@ -0,0 +1,163 @@
/*-
* Copyright (c) 2009 Jared D. McNeill <jmcneill@invisible.ca>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Default mode for VESA frame buffer.
* This mode is selected when there is no EDID inormation and
* mode is not provided by user.
* To provide consistent look with UEFI GOP, we use 800x600 here,
* and if this mode is not available, we fall back to text mode and
* VESA disabled.
*/
#define VBE_DEFAULT_MODE "800x600"
struct vbeinfoblock {
char VbeSignature[4];
uint16_t VbeVersion;
uint32_t OemStringPtr;
uint32_t Capabilities;
#define VBE_CAP_DAC8 (1 << 0) /* Can switch DAC */
#define VBE_CAP_NONVGA (1 << 1) /* Controller is not VGA comp. */
#define VBE_CAP_SNOW (1 << 2) /* Set data during Vertical Reterace */
uint32_t VideoModePtr;
uint16_t TotalMemory;
uint16_t OemSoftwareRev;
uint32_t OemVendorNamePtr, OemProductNamePtr, OemProductRevPtr;
/* data area, in total max 512 bytes for VBE 2.0 */
uint8_t Reserved[222];
uint8_t OemData[256];
} __packed;
struct modeinfoblock {
/* Mandatory information for all VBE revisions */
uint16_t ModeAttributes;
uint8_t WinAAttributes, WinBAttributes;
uint16_t WinGranularity, WinSize, WinASegment, WinBSegment;
uint32_t WinFuncPtr;
uint16_t BytesPerScanLine;
/* Mandatory information for VBE 1.2 and above */
uint16_t XResolution, YResolution;
uint8_t XCharSize, YCharSize, NumberOfPlanes, BitsPerPixel;
uint8_t NumberOfBanks, MemoryModel, BankSize, NumberOfImagePages;
uint8_t Reserved1;
/* Direct Color fields
(required for direct/6 and YUV/7 memory models) */
uint8_t RedMaskSize, RedFieldPosition;
uint8_t GreenMaskSize, GreenFieldPosition;
uint8_t BlueMaskSize, BlueFieldPosition;
uint8_t RsvdMaskSize, RsvdFieldPosition;
uint8_t DirectColorModeInfo;
/* Mandatory information for VBE 2.0 and above */
uint32_t PhysBasePtr;
uint32_t OffScreenMemOffset; /* reserved in VBE 3.0 and above */
uint16_t OffScreenMemSize; /* reserved in VBE 3.0 and above */
/* Mandatory information for VBE 3.0 and above */
uint16_t LinBytesPerScanLine;
uint8_t BnkNumberOfImagePages;
uint8_t LinNumberOfImagePages;
uint8_t LinRedMaskSize, LinRedFieldPosition;
uint8_t LinGreenMaskSize, LinGreenFieldPosition;
uint8_t LinBlueMaskSize, LinBlueFieldPosition;
uint8_t LinRsvdMaskSize, LinRsvdFieldPosition;
uint32_t MaxPixelClock;
/* + 1 will fix the size to 256 bytes */
uint8_t Reserved4[189 + 1];
} __packed;
struct crtciinfoblock {
uint16_t HorizontalTotal;
uint16_t HorizontalSyncStart;
uint16_t HorizontalSyncEnd;
uint16_t VerticalTotal;
uint16_t VerticalSyncStart;
uint16_t VerticalSyncEnd;
uint8_t Flags;
uint32_t PixelClock;
uint16_t RefreshRate;
uint8_t Reserved[40];
} __packed;
struct paletteentry {
uint8_t Blue;
uint8_t Green;
uint8_t Red;
uint8_t Reserved;
} __packed;
struct flatpanelinfo
{
uint16_t HorizontalSize;
uint16_t VerticalSize;
uint16_t PanelType;
uint8_t RedBPP;
uint8_t GreenBPP;
uint8_t BlueBPP;
uint8_t ReservedBPP;
uint32_t ReservedOffScreenMemSize;
uint32_t ReservedOffScreenMemPtr;
uint8_t Reserved[14];
} __packed;
#define VBE_BASE_MODE (0x100) /* VBE 3.0 page 18 */
#define VBE_VALID_MODE(a) ((a) >= VBE_BASE_MODE)
#define VBE_ERROR(a) (((a) & 0xFF) != 0x4F || ((a) & 0xFF00) != 0)
#define VBE_SUCCESS (0x004F)
#define VBE_FAILED (0x014F)
#define VBE_NOTSUP (0x024F)
#define VBE_INVALID (0x034F)
#define VGA_TEXT_MODE (3) /* 80x25 text mode */
#define TEXT_ROWS (25) /* VGATEXT rows */
#define TEXT_COLS (80) /* VGATEXT columns */
extern struct paletteentry *pe8;
extern int palette_format;
int vga_get_reg(int, int);
int vga_get_atr(int, int);
void vga_set_atr(int, int, int);
void vga_set_indexed(int, int, int, uint8_t, uint8_t);
int vga_get_indexed(int, int, int, uint8_t);
int vga_get_crtc(int, int);
void vga_set_crtc(int, int, int);
int vga_get_seq(int, int);
void vga_set_seq(int, int, int);
int vga_get_grc(int, int);
void vga_set_grc(int, int, int);
/* high-level VBE helpers, from vbe.c */
void bios_set_text_mode(int);
int biosvbe_palette_format(int *);
void vbe_init(void);
bool vbe_available(void);
int vbe_default_mode(void);
int vbe_set_mode(int);
int vbe_get_mode(void);
int vbe_set_palette(const struct paletteentry *, size_t);
void vbe_modelist(int);

View File

@ -31,12 +31,13 @@
__FBSDID("$FreeBSD$"); __FBSDID("$FreeBSD$");
#include <stand.h> #include <stand.h>
#include <sys/param.h>
#include <bootstrap.h> #include <bootstrap.h>
#include <btxv86.h> #include <btxv86.h>
#include <machine/psl.h> #include <gfx_fb.h>
#include <machine/cpufunc.h>
#include <teken.h> #include <teken.h>
#include <stdbool.h> #include <stdbool.h>
#include "vbe.h"
#include <dev/vt/hw/vga/vt_vga_reg.h> #include <dev/vt/hw/vga/vt_vga_reg.h>
@ -50,6 +51,7 @@ static int vidc_init(int arg);
static void vidc_putchar(int c); static void vidc_putchar(int c);
static int vidc_getchar(void); static int vidc_getchar(void);
static int vidc_ischar(void); static int vidc_ischar(void);
static void cons_draw_frame(teken_attr_t *);
static int vidc_started; static int vidc_started;
static uint16_t *vgatext; static uint16_t *vgatext;
@ -72,30 +74,16 @@ static teken_funcs_t tf = {
.tf_respond = vidc_cons_respond, .tf_respond = vidc_cons_respond,
}; };
teken_t teken; static teken_funcs_t tfx = {
teken_pos_t tp; .tf_bell = vidc_cons_bell,
.tf_cursor = gfx_fb_cursor,
struct text_pixel { .tf_putchar = gfx_fb_putchar,
teken_char_t c; .tf_fill = gfx_fb_fill,
teken_attr_t a; .tf_copy = gfx_fb_copy,
.tf_param = gfx_fb_param,
.tf_respond = vidc_cons_respond,
}; };
static struct text_pixel *buffer;
#define NCOLORS 16
/*
* Between console's palette and VGA's one:
* - blue and red are swapped (1 <-> 4)
* - yellow and cyan are swapped (3 <-> 6)
*/
static const int cons_to_vga_colors[NCOLORS] = {
0, 4, 2, 6, 1, 5, 3, 7,
8, 12, 10, 14, 9, 13, 11, 15
};
#define TEXT_COLS 80
#define TEXT_ROWS 25
#define KEYBUFSZ 10 #define KEYBUFSZ 10
static uint8_t keybuf[KEYBUFSZ]; /* keybuf for extended codes */ static uint8_t keybuf[KEYBUFSZ]; /* keybuf for extended codes */
@ -111,60 +99,26 @@ struct console vidconsole = {
.c_ready = vidc_ischar .c_ready = vidc_ischar
}; };
static int /*
vga_get_reg(int reg, int index) * This function is used to mark a rectangular image area so the scrolling
* will know we need to copy the data from there.
*/
void
term_image_display(teken_gfx_t *state, const teken_rect_t *r)
{ {
return (inb(reg + index)); teken_pos_t p;
int idx;
for (p.tp_row = r->tr_begin.tp_row;
p.tp_row < r->tr_end.tp_row; p.tp_row++) {
for (p.tp_col = r->tr_begin.tp_col;
p.tp_col < r->tr_end.tp_col; p.tp_col++) {
idx = p.tp_col + p.tp_row * state->tg_tp.tp_col;
if (idx >= state->tg_tp.tp_col * state->tg_tp.tp_row)
return;
screen_buffer[idx].a.ta_format |= TF_IMAGE;
} }
static int
vga_get_atr(int reg, int i)
{
int ret;
(void) inb(reg + VGA_GEN_INPUT_STAT_1);
outb(reg + VGA_AC_WRITE, i);
ret = inb(reg + VGA_AC_READ);
(void) inb(reg + VGA_GEN_INPUT_STAT_1);
return (ret);
} }
static void
vga_set_atr(int reg, int i, int v)
{
(void) inb(reg + VGA_GEN_INPUT_STAT_1);
outb(reg + VGA_AC_WRITE, i);
outb(reg + VGA_AC_WRITE, v);
(void) inb(reg + VGA_GEN_INPUT_STAT_1);
}
static void
vga_set_indexed(int reg, int indexreg, int datareg, uint8_t index, uint8_t val)
{
outb(reg + indexreg, index);
outb(reg + datareg, val);
}
static int
vga_get_indexed(int reg, int indexreg, int datareg, uint8_t index)
{
outb(reg + indexreg, index);
return (inb(reg + datareg));
}
static int
vga_get_crtc(int reg, int i)
{
return (vga_get_indexed(reg, VGA_CRTC_ADDRESS, VGA_CRTC_DATA, i));
}
static void
vga_set_crtc(int reg, int i, int v)
{
vga_set_indexed(reg, VGA_CRTC_ADDRESS, VGA_CRTC_DATA, i, v);
} }
static void static void
@ -353,9 +307,9 @@ vga_get_cp437(teken_char_t c)
} }
static void static void
vidc_text_printchar(const teken_pos_t *p) vidc_text_printchar(teken_gfx_t *state, const teken_pos_t *p)
{ {
int i; int idx;
uint8_t attr; uint8_t attr;
struct text_pixel *px; struct text_pixel *px;
teken_color_t fg, bg, tmp; teken_color_t fg, bg, tmp;
@ -364,7 +318,8 @@ vidc_text_printchar(const teken_pos_t *p)
uint8_t attr; uint8_t attr;
} *addr; } *addr;
px = buffer + p->tp_col + p->tp_row * tp.tp_col; idx = p->tp_col + p->tp_row * state->tg_tp.tp_col;
px = &screen_buffer[idx];
fg = teken_256to16(px->a.ta_fgcolor); fg = teken_256to16(px->a.ta_fgcolor);
bg = teken_256to16(px->a.ta_bgcolor); bg = teken_256to16(px->a.ta_bgcolor);
if (px->a.ta_format & TF_BOLD) if (px->a.ta_format & TF_BOLD)
@ -378,29 +333,34 @@ vidc_text_printchar(const teken_pos_t *p)
bg = tmp; bg = tmp;
} }
attr = (cons_to_vga_colors[bg & 0xf] << 4) | attr = (cmap[bg & 0xf] << 4) | cmap[fg & 0xf];
cons_to_vga_colors[fg & 0xf]; addr = (struct cgatext *)vgatext;
addr = (struct cgatext *)vgatext + p->tp_col + p->tp_row * tp.tp_col; addr[idx].ch = vga_get_cp437(px->c);
addr->ch = vga_get_cp437(px->c); addr[idx].attr = attr;
addr->attr = attr;
} }
static void static void
vidc_text_putchar(void *s __unused, const teken_pos_t *p, teken_char_t c, vidc_text_putchar(void *s, const teken_pos_t *p, teken_char_t c,
const teken_attr_t *a) const teken_attr_t *a)
{ {
teken_gfx_t *state = s;
int attr, idx; int attr, idx;
idx = p->tp_col + p->tp_row * tp.tp_col; idx = p->tp_col + p->tp_row * state->tg_tp.tp_col;
buffer[idx].c = c; if (idx >= state->tg_tp.tp_col * state->tg_tp.tp_row)
buffer[idx].a = *a; return;
vidc_text_printchar(p);
screen_buffer[idx].c = c;
screen_buffer[idx].a = *a;
vidc_text_printchar(state, p);
} }
static void static void
vidc_text_fill(void *s, const teken_rect_t *r, teken_char_t c, vidc_text_fill(void *arg, const teken_rect_t *r, teken_char_t c,
const teken_attr_t *a) const teken_attr_t *a)
{ {
teken_gfx_t *state = arg;
teken_pos_t p; teken_pos_t p;
teken_unit_t row, col; teken_unit_t row, col;
@ -410,29 +370,14 @@ vidc_text_fill(void *s, const teken_rect_t *r, teken_char_t c,
p.tp_row++) p.tp_row++)
for (p.tp_col = r->tr_begin.tp_col; for (p.tp_col = r->tr_begin.tp_col;
p.tp_col < r->tr_end.tp_col; p.tp_col++) p.tp_col < r->tr_end.tp_col; p.tp_col++)
vidc_text_putchar(s, &p, c, a); vidc_text_putchar(state, &p, c, a);
vidc_text_set_cursor(row, col, true); vidc_text_set_cursor(row, col, true);
} }
static bool
vidc_same_pixel(struct text_pixel *px1, struct text_pixel *px2)
{
if (px1->c != px2->c)
return (false);
if (px1->a.ta_format != px2->a.ta_format)
return (false);
if (px1->a.ta_fgcolor != px2->a.ta_fgcolor)
return (false);
if (px1->a.ta_bgcolor != px2->a.ta_bgcolor)
return (false);
return (true);
}
static void static void
vidc_text_copy(void *ptr __unused, const teken_rect_t *r, const teken_pos_t *p) vidc_text_copy(void *ptr, const teken_rect_t *r, const teken_pos_t *p)
{ {
teken_gfx_t *state = ptr;
int srow, drow; int srow, drow;
int nrow, ncol, x, y; /* Has to be signed - >= 0 comparison */ int nrow, ncol, x, y; /* Has to be signed - >= 0 comparison */
teken_pos_t d, s; teken_pos_t d, s;
@ -453,18 +398,18 @@ vidc_text_copy(void *ptr __unused, const teken_rect_t *r, const teken_pos_t *p)
for (y = 0; y < nrow; y++) { for (y = 0; y < nrow; y++) {
d.tp_row = p->tp_row + y; d.tp_row = p->tp_row + y;
s.tp_row = r->tr_begin.tp_row + y; s.tp_row = r->tr_begin.tp_row + y;
drow = d.tp_row * tp.tp_col; drow = d.tp_row * state->tg_tp.tp_col;
srow = s.tp_row * tp.tp_col; srow = s.tp_row * state->tg_tp.tp_col;
for (x = 0; x < ncol; x++) { for (x = 0; x < ncol; x++) {
d.tp_col = p->tp_col + x; d.tp_col = p->tp_col + x;
s.tp_col = r->tr_begin.tp_col + x; s.tp_col = r->tr_begin.tp_col + x;
if (!vidc_same_pixel( if (!is_same_pixel(
&buffer[d.tp_col + drow], &screen_buffer[d.tp_col + drow],
&buffer[s.tp_col + srow])) { &screen_buffer[s.tp_col + srow])) {
buffer[d.tp_col + drow] = screen_buffer[d.tp_col + drow] =
buffer[s.tp_col + srow]; screen_buffer[s.tp_col + srow];
vidc_text_printchar(&d); vidc_text_printchar(state, &d);
} }
} }
} }
@ -475,18 +420,18 @@ vidc_text_copy(void *ptr __unused, const teken_rect_t *r, const teken_pos_t *p)
for (y = nrow - 1; y >= 0; y--) { for (y = nrow - 1; y >= 0; y--) {
d.tp_row = p->tp_row + y; d.tp_row = p->tp_row + y;
s.tp_row = r->tr_begin.tp_row + y; s.tp_row = r->tr_begin.tp_row + y;
drow = d.tp_row * tp.tp_col; drow = d.tp_row * state->tg_tp.tp_col;
srow = s.tp_row * tp.tp_col; srow = s.tp_row * state->tg_tp.tp_col;
for (x = 0; x < ncol; x++) { for (x = 0; x < ncol; x++) {
d.tp_col = p->tp_col + x; d.tp_col = p->tp_col + x;
s.tp_col = r->tr_begin.tp_col + x; s.tp_col = r->tr_begin.tp_col + x;
if (!vidc_same_pixel( if (!is_same_pixel(
&buffer[d.tp_col + drow], &screen_buffer[d.tp_col + drow],
&buffer[s.tp_col + srow])) { &screen_buffer[s.tp_col + srow])) {
buffer[d.tp_col + drow] = screen_buffer[d.tp_col + drow] =
buffer[s.tp_col + srow]; screen_buffer[s.tp_col + srow];
vidc_text_printchar(&d); vidc_text_printchar(state, &d);
} }
} }
} }
@ -495,18 +440,18 @@ vidc_text_copy(void *ptr __unused, const teken_rect_t *r, const teken_pos_t *p)
for (y = nrow - 1; y >= 0; y--) { for (y = nrow - 1; y >= 0; y--) {
d.tp_row = p->tp_row + y; d.tp_row = p->tp_row + y;
s.tp_row = r->tr_begin.tp_row + y; s.tp_row = r->tr_begin.tp_row + y;
drow = d.tp_row * tp.tp_col; drow = d.tp_row * state->tg_tp.tp_col;
srow = s.tp_row * tp.tp_col; srow = s.tp_row * state->tg_tp.tp_col;
for (x = ncol - 1; x >= 0; x--) { for (x = ncol - 1; x >= 0; x--) {
d.tp_col = p->tp_col + x; d.tp_col = p->tp_col + x;
s.tp_col = r->tr_begin.tp_col + x; s.tp_col = r->tr_begin.tp_col + x;
if (!vidc_same_pixel( if (!is_same_pixel(
&buffer[d.tp_col + drow], &screen_buffer[d.tp_col + drow],
&buffer[s.tp_col + srow])) { &screen_buffer[s.tp_col + srow])) {
buffer[d.tp_col + drow] = screen_buffer[d.tp_col + drow] =
buffer[s.tp_col + srow]; screen_buffer[s.tp_col + srow];
vidc_text_printchar(&d); vidc_text_printchar(state, &d);
} }
} }
} }
@ -516,8 +461,9 @@ vidc_text_copy(void *ptr __unused, const teken_rect_t *r, const teken_pos_t *p)
} }
static void static void
vidc_text_param(void *s __unused, int cmd, unsigned int value) vidc_text_param(void *arg, int cmd, unsigned int value)
{ {
teken_gfx_t *state = arg;
teken_unit_t row, col; teken_unit_t row, col;
switch (cmd) { switch (cmd) {
@ -532,10 +478,13 @@ vidc_text_param(void *s __unused, int cmd, unsigned int value)
/* FALLTHROUGH */ /* FALLTHROUGH */
case TP_SHOWCURSOR: case TP_SHOWCURSOR:
vidc_text_get_cursor(&row, &col); vidc_text_get_cursor(&row, &col);
if (value == 1) if (value != 0) {
vidc_text_set_cursor(row, col, true); vidc_text_set_cursor(row, col, true);
else state->tg_cursor_visible = true;
} else {
vidc_text_set_cursor(row, col, false); vidc_text_set_cursor(row, col, false);
state->tg_cursor_visible = false;
}
break; break;
default: default:
/* Not yet implemented */ /* Not yet implemented */
@ -635,7 +584,7 @@ vidc_set_colors(struct env_var *ev, int flags, const void *value)
evalue = value; evalue = value;
} }
ap = teken_get_defattr(&teken); ap = teken_get_defattr(&gfx_state.tg_teken);
a = *ap; a = *ap;
if (strcmp(ev->ev_name, "teken.fg_color") == 0) { if (strcmp(ev->ev_name, "teken.fg_color") == 0) {
/* is it already set? */ /* is it already set? */
@ -654,11 +603,381 @@ vidc_set_colors(struct env_var *ev, int flags, const void *value)
if (a.ta_bgcolor == TC_WHITE) if (a.ta_bgcolor == TC_WHITE)
a.ta_bgcolor |= TC_LIGHT; a.ta_bgcolor |= TC_LIGHT;
teken_set_defattr(&gfx_state.tg_teken, &a);
cons_draw_frame(&a);
env_setenv(ev->ev_name, flags | EV_NOHOOK, evalue, NULL, NULL); env_setenv(ev->ev_name, flags | EV_NOHOOK, evalue, NULL, NULL);
teken_set_defattr(&teken, &a); teken_input(&gfx_state.tg_teken, "\e[2J", 4);
return (CMD_OK); return (CMD_OK);
} }
static int
env_screen_nounset(struct env_var *ev __unused)
{
if (gfx_state.tg_fb_type == FB_TEXT)
return (0);
return (EPERM);
}
static int
vidc_load_palette(uint32_t *cmap)
{
int i, roff, goff, boff, rc;
if (pe8 == NULL)
pe8 = calloc(sizeof(*pe8), NCMAP);
if (pe8 == NULL)
return (ENOMEM);
/* Generate VGA colors */
roff = ffs(gfx_state.tg_fb.fb_mask_red) - 1;
goff = ffs(gfx_state.tg_fb.fb_mask_green) - 1;
boff = ffs(gfx_state.tg_fb.fb_mask_blue) - 1;
rc = generate_cons_palette((uint32_t *)pe8, COLOR_FORMAT_RGB,
gfx_state.tg_fb.fb_mask_red >> roff, roff,
gfx_state.tg_fb.fb_mask_green >> goff, goff,
gfx_state.tg_fb.fb_mask_blue >> boff, boff);
if (rc == 0) {
for (i = 0; i < NCMAP; i++) {
int idx;
if (i < NCOLORS)
idx = cons_to_vga_colors[i];
else
idx = i;
rc = vbe_set_palette(&pe8[i], idx);
if (rc != 0)
break;
}
}
return (rc);
}
static void
cons_draw_frame(teken_attr_t *a)
{
teken_attr_t attr = *a;
teken_color_t fg = a->ta_fgcolor;
attr.ta_fgcolor = attr.ta_bgcolor;
teken_set_defattr(&gfx_state.tg_teken, &attr);
gfx_fb_drawrect(0, 0, gfx_state.tg_fb.fb_width,
gfx_state.tg_origin.tp_row, 1);
gfx_fb_drawrect(0,
gfx_state.tg_fb.fb_height - gfx_state.tg_origin.tp_row - 1,
gfx_state.tg_fb.fb_width, gfx_state.tg_fb.fb_height, 1);
gfx_fb_drawrect(0, gfx_state.tg_origin.tp_row,
gfx_state.tg_origin.tp_col,
gfx_state.tg_fb.fb_height - gfx_state.tg_origin.tp_row - 1, 1);
gfx_fb_drawrect(
gfx_state.tg_fb.fb_width - gfx_state.tg_origin.tp_col - 1,
gfx_state.tg_origin.tp_row, gfx_state.tg_fb.fb_width,
gfx_state.tg_fb.fb_height, 1);
attr.ta_fgcolor = fg;
teken_set_defattr(&gfx_state.tg_teken, &attr);
}
/*
* Binary searchable table for CP437 to Unicode conversion.
*/
struct cp437uni {
uint8_t cp437_base;
uint16_t unicode_base;
uint8_t length;
};
static const struct cp437uni cp437unitable[] = {
{ 0, 0x0000, 0 }, { 1, 0x263A, 1 }, { 3, 0x2665, 1 },
{ 5, 0x2663, 0 }, { 6, 0x2660, 0 }, { 7, 0x2022, 0 },
{ 8, 0x25D8, 0 }, { 9, 0x25CB, 0 }, { 10, 0x25D9, 0 },
{ 11, 0x2642, 0 }, { 12, 0x2640, 0 }, { 13, 0x266A, 1 },
{ 15, 0x263C, 0 }, { 16, 0x25BA, 0 }, { 17, 0x25C4, 0 },
{ 18, 0x2195, 0 }, { 19, 0x203C, 0 }, { 20, 0x00B6, 0 },
{ 21, 0x00A7, 0 }, { 22, 0x25AC, 0 }, { 23, 0x21A8, 0 },
{ 24, 0x2191, 0 }, { 25, 0x2193, 0 }, { 26, 0x2192, 0 },
{ 27, 0x2190, 0 }, { 28, 0x221F, 0 }, { 29, 0x2194, 0 },
{ 30, 0x25B2, 0 }, { 31, 0x25BC, 0 }, { 32, 0x0020, 0x5e },
{ 127, 0x2302, 0 }, { 128, 0x00C7, 0 }, { 129, 0x00FC, 0 },
{ 130, 0x00E9, 0 }, { 131, 0x00E2, 0 }, { 132, 0x00E4, 0 },
{ 133, 0x00E0, 0 }, { 134, 0x00E5, 0 }, { 135, 0x00E7, 0 },
{ 136, 0x00EA, 1 }, { 138, 0x00E8, 0 }, { 139, 0x00EF, 0 },
{ 140, 0x00EE, 0 }, { 141, 0x00EC, 0 }, { 142, 0x00C4, 1 },
{ 144, 0x00C9, 0 }, { 145, 0x00E6, 0 }, { 146, 0x00C6, 0 },
{ 147, 0x00F4, 0 }, { 148, 0x00F6, 0 }, { 149, 0x00F2, 0 },
{ 150, 0x00FB, 0 }, { 151, 0x00F9, 0 }, { 152, 0x00FF, 0 },
{ 153, 0x00D6, 0 }, { 154, 0x00DC, 0 }, { 155, 0x00A2, 1 },
{ 157, 0x00A5, 0 }, { 158, 0x20A7, 0 }, { 159, 0x0192, 0 },
{ 160, 0x00E1, 0 }, { 161, 0x00ED, 0 }, { 162, 0x00F3, 0 },
{ 163, 0x00FA, 0 }, { 164, 0x00F1, 0 }, { 165, 0x00D1, 0 },
{ 166, 0x00AA, 0 }, { 167, 0x00BA, 0 }, { 168, 0x00BF, 0 },
{ 169, 0x2310, 0 }, { 170, 0x00AC, 0 }, { 171, 0x00BD, 0 },
{ 172, 0x00BC, 0 }, { 173, 0x00A1, 0 }, { 174, 0x00AB, 0 },
{ 175, 0x00BB, 0 }, { 176, 0x2591, 2 }, { 179, 0x2502, 0 },
{ 180, 0x2524, 0 }, { 181, 0x2561, 1 }, { 183, 0x2556, 0 },
{ 184, 0x2555, 0 }, { 185, 0x2563, 0 }, { 186, 0x2551, 0 },
{ 187, 0x2557, 0 }, { 188, 0x255D, 0 }, { 189, 0x255C, 0 },
{ 190, 0x255B, 0 }, { 191, 0x2510, 0 }, { 192, 0x2514, 0 },
{ 193, 0x2534, 0 }, { 194, 0x252C, 0 }, { 195, 0x251C, 0 },
{ 196, 0x2500, 0 }, { 197, 0x253C, 0 }, { 198, 0x255E, 1 },
{ 200, 0x255A, 0 }, { 201, 0x2554, 0 }, { 202, 0x2569, 0 },
{ 203, 0x2566, 0 }, { 204, 0x2560, 0 }, { 205, 0x2550, 0 },
{ 206, 0x256C, 0 }, { 207, 0x2567, 1 }, { 209, 0x2564, 1 },
{ 211, 0x2559, 0 }, { 212, 0x2558, 0 }, { 213, 0x2552, 1 },
{ 215, 0x256B, 0 }, { 216, 0x256A, 0 }, { 217, 0x2518, 0 },
{ 218, 0x250C, 0 }, { 219, 0x2588, 0 }, { 220, 0x2584, 0 },
{ 221, 0x258C, 0 }, { 222, 0x2590, 0 }, { 223, 0x2580, 0 },
{ 224, 0x03B1, 0 }, { 225, 0x00DF, 0 }, { 226, 0x0393, 0 },
{ 227, 0x03C0, 0 }, { 228, 0x03A3, 0 }, { 229, 0x03C3, 0 },
{ 230, 0x00B5, 0 }, { 231, 0x03C4, 0 }, { 232, 0x03A6, 0 },
{ 233, 0x0398, 0 }, { 234, 0x03A9, 0 }, { 235, 0x03B4, 0 },
{ 236, 0x221E, 0 }, { 237, 0x03C6, 0 }, { 238, 0x03B5, 0 },
{ 239, 0x2229, 0 }, { 240, 0x2261, 0 }, { 241, 0x00B1, 0 },
{ 242, 0x2265, 0 }, { 243, 0x2264, 0 }, { 244, 0x2320, 1 },
{ 246, 0x00F7, 0 }, { 247, 0x2248, 0 }, { 248, 0x00B0, 0 },
{ 249, 0x2219, 0 }, { 250, 0x00B7, 0 }, { 251, 0x221A, 0 },
{ 252, 0x207F, 0 }, { 253, 0x00B2, 0 }, { 254, 0x25A0, 0 },
{ 255, 0x00A0, 0 }
};
static uint16_t
vga_cp437_to_uni(uint8_t c)
{
int min, mid, max;
min = 0;
max = (sizeof(cp437unitable) / sizeof(struct cp437uni)) - 1;
while (max >= min) {
mid = (min + max) / 2;
if (c < cp437unitable[mid].cp437_base)
max = mid - 1;
else if (c > cp437unitable[mid].cp437_base +
cp437unitable[mid].length)
min = mid + 1;
else
return (c - cp437unitable[mid].cp437_base +
cp437unitable[mid].unicode_base);
}
return ('?');
}
/*
* install font for text mode
*/
static void
vidc_install_font(void)
{
static uint8_t fsreg[8] = {0x0, 0x30, 0x5, 0x35, 0xa, 0x3a, 0xf, 0x3f};
const uint8_t *from;
uint8_t volatile *to;
uint16_t c;
int i, j, s;
int bpc, f_offset;
teken_attr_t a = { 0 };
if (gfx_state.tg_fb_type != FB_TEXT)
return;
/* Sync-reset the sequencer registers */
vga_set_seq(VGA_REG_BASE, 0x00, 0x01);
/*
* enable write to plane2, since fonts
* could only be loaded into plane2
*/
vga_set_seq(VGA_REG_BASE, 0x02, 0x04);
/*
* sequentially access data in the bit map being
* selected by MapMask register (index 0x02)
*/
vga_set_seq(VGA_REG_BASE, 0x04, 0x07);
/* Sync-reset ended, and allow the sequencer to operate */
vga_set_seq(VGA_REG_BASE, 0x00, 0x03);
/*
* select plane 2 on Read Mode 0
*/
vga_set_grc(VGA_REG_BASE, 0x04, 0x02);
/*
* system addresses sequentially access data, follow
* Memory Mode register bit 2 in the sequencer
*/
vga_set_grc(VGA_REG_BASE, 0x05, 0x00);
/*
* set range of host memory addresses decoded by VGA
* hardware -- A0000h-BFFFFh (128K region)
*/
vga_set_grc(VGA_REG_BASE, 0x06, 0x00);
/*
* This assumes 8x16 characters, which yield the traditional 80x25
* screen.
*/
bpc = 16;
s = 0; /* font slot, maybe should use tunable there. */
f_offset = s * 8 * 1024;
for (i = 0; i < 256; i++) {
c = vga_cp437_to_uni(i);
from = font_lookup(&gfx_state.tg_font, c, &a);
to = (unsigned char *)ptov(VGA_MEM_BASE) + f_offset +
i * 0x20;
for (j = 0; j < bpc; j++)
*to++ = *from++;
}
/* Sync-reset the sequencer registers */
vga_set_seq(VGA_REG_BASE, 0x00, 0x01);
/* enable write to plane 0 and 1 */
vga_set_seq(VGA_REG_BASE, 0x02, 0x03);
/*
* enable character map selection
* and odd/even addressing
*/
vga_set_seq(VGA_REG_BASE, 0x04, 0x03);
/*
* select font map
*/
vga_set_seq(VGA_REG_BASE, 0x03, fsreg[s]);
/* Sync-reset ended, and allow the sequencer to operate */
vga_set_seq(VGA_REG_BASE, 0x00, 0x03);
/* restore graphic registers */
/* select plane 0 */
vga_set_grc(VGA_REG_BASE, 0x04, 0x00);
/* enable odd/even addressing mode */
vga_set_grc(VGA_REG_BASE, 0x05, 0x10);
/*
* range of host memory addresses decoded by VGA
* hardware -- B8000h-BFFFFh (32K region)
*/
vga_set_grc(VGA_REG_BASE, 0x06, 0x0e);
/* enable all color plane */
vga_set_atr(VGA_REG_BASE, 0x12, 0x0f);
}
bool
cons_update_mode(bool use_gfx_mode)
{
const teken_attr_t *a;
teken_attr_t attr;
char env[10], *ptr;
int format, roff, goff, boff;
gfx_state.tg_tp.tp_row = TEXT_ROWS;
gfx_state.tg_tp.tp_col = TEXT_COLS;
if (use_gfx_mode) {
setup_font(&gfx_state, gfx_state.tg_fb.fb_height,
gfx_state.tg_fb.fb_width);
/* Point of origin in pixels. */
gfx_state.tg_origin.tp_row = (gfx_state.tg_fb.fb_height -
(gfx_state.tg_tp.tp_row * gfx_state.tg_font.vf_height)) / 2;
gfx_state.tg_origin.tp_col = (gfx_state.tg_fb.fb_width -
(gfx_state.tg_tp.tp_col * gfx_state.tg_font.vf_width)) / 2;
gfx_state.tg_glyph_size = gfx_state.tg_font.vf_height *
gfx_state.tg_font.vf_width * 4;
free(gfx_state.tg_glyph);
gfx_state.tg_glyph = malloc(gfx_state.tg_glyph_size);
if (gfx_state.tg_glyph == NULL)
return (false);
gfx_state.tg_functions = &tfx;
snprintf(env, sizeof (env), "%d", gfx_state.tg_fb.fb_height);
env_setenv("screen.height", EV_VOLATILE | EV_NOHOOK, env,
env_noset, env_screen_nounset);
snprintf(env, sizeof (env), "%d", gfx_state.tg_fb.fb_width);
env_setenv("screen.width", EV_VOLATILE | EV_NOHOOK, env,
env_noset, env_screen_nounset);
snprintf(env, sizeof (env), "%d", gfx_state.tg_fb.fb_bpp);
env_setenv("screen.depth", EV_VOLATILE | EV_NOHOOK, env,
env_noset, env_screen_nounset);
} else {
/* Trigger loading of 8x16 font. */
setup_font(&gfx_state,
16 * gfx_state.tg_fb.fb_height + BORDER_PIXELS,
8 * gfx_state.tg_fb.fb_width + BORDER_PIXELS);
gfx_state.tg_functions = &tf;
/* ensure the following are not set for text mode */
unsetenv("screen.height");
unsetenv("screen.width");
unsetenv("screen.depth");
unsetenv("kern.vt.fb.default_mode");
vidc_install_font();
}
free(screen_buffer);
screen_buffer = malloc(gfx_state.tg_tp.tp_row * gfx_state.tg_tp.tp_col *
sizeof(*screen_buffer));
if (screen_buffer == NULL)
return (false);
teken_init(&gfx_state.tg_teken, gfx_state.tg_functions, &gfx_state);
if (gfx_state.tg_ctype == CT_INDEXED)
format = COLOR_FORMAT_VGA;
else
format = COLOR_FORMAT_RGB;
roff = ffs(gfx_state.tg_fb.fb_mask_red) - 1;
goff = ffs(gfx_state.tg_fb.fb_mask_green) - 1;
boff = ffs(gfx_state.tg_fb.fb_mask_blue) - 1;
(void) generate_cons_palette(cmap, format,
gfx_state.tg_fb.fb_mask_red >> roff, roff,
gfx_state.tg_fb.fb_mask_green >> goff, goff,
gfx_state.tg_fb.fb_mask_blue >> boff, boff);
if (gfx_state.tg_ctype == CT_INDEXED)
vidc_load_palette(cmap);
teken_set_winsize(&gfx_state.tg_teken, &gfx_state.tg_tp);
a = teken_get_defattr(&gfx_state.tg_teken);
attr = *a;
/*
* On first run, we set up the vidc_set_colors()
* callback. If the env is already set, we
* pick up fg and bg color values from the environment.
*/
ptr = getenv("teken.fg_color");
if (ptr != NULL) {
attr.ta_fgcolor = strtol(ptr, NULL, 10);
ptr = getenv("teken.bg_color");
attr.ta_bgcolor = strtol(ptr, NULL, 10);
teken_set_defattr(&gfx_state.tg_teken, &attr);
} else {
snprintf(env, sizeof(env), "%d", attr.ta_fgcolor);
env_setenv("teken.fg_color", EV_VOLATILE, env,
vidc_set_colors, env_nounset);
snprintf(env, sizeof(env), "%d", attr.ta_bgcolor);
env_setenv("teken.bg_color", EV_VOLATILE, env,
vidc_set_colors, env_nounset);
}
/* Improve visibility */
if (attr.ta_bgcolor == TC_WHITE)
attr.ta_bgcolor |= TC_LIGHT;
teken_set_defattr(&gfx_state.tg_teken, &attr);
snprintf(env, sizeof (env), "%u", (unsigned)gfx_state.tg_tp.tp_row);
setenv("LINES", env, 1);
snprintf(env, sizeof (env), "%u", (unsigned)gfx_state.tg_tp.tp_col);
setenv("COLUMNS", env, 1);
/* Draw frame around terminal area. */
cons_draw_frame(&attr);
/* Erase display, this will also fill our screen buffer. */
teken_input(&gfx_state.tg_teken, "\e[2J", 4);
gfx_state.tg_functions->tf_param(&gfx_state, TP_SHOWCURSOR, 1);
return (true);
}
static int static int
vidc_init(int arg) vidc_init(int arg)
{ {
@ -670,6 +989,7 @@ vidc_init(int arg)
return (0); return (0);
vidc_started = 1; vidc_started = 1;
vbe_init();
/* /*
* Check Miscellaneous Output Register (Read at 3CCh, Write at 3C2h) * Check Miscellaneous Output Register (Read at 3CCh, Write at 3C2h)
@ -687,31 +1007,20 @@ vidc_init(int arg)
val &= ~VGA_AC_MC_ELG; val &= ~VGA_AC_MC_ELG;
vga_set_atr(VGA_REG_BASE, VGA_AC_MODE_CONTROL, val); vga_set_atr(VGA_REG_BASE, VGA_AC_MODE_CONTROL, val);
tp.tp_row = TEXT_ROWS; #if defined(FRAMEBUFFER_MODE)
tp.tp_col = TEXT_COLS; val = vbe_default_mode();
buffer = malloc(tp.tp_row * tp.tp_col * sizeof(*buffer)); /* if val is not legal VBE mode, use text mode */
if (buffer == NULL) if (VBE_VALID_MODE(val)) {
if (vbe_set_mode(val) != 0)
bios_set_text_mode(VGA_TEXT_MODE);
}
#endif
gfx_framework_init();
if (!cons_update_mode(VBE_VALID_MODE(vbe_get_mode())))
return (1); return (1);
snprintf(env, sizeof (env), "%u", tp.tp_row);
setenv("LINES", env, 1);
snprintf(env, sizeof (env), "%u", tp.tp_col);
setenv("COLUMNS", env, 1);
teken_init(&teken, &tf, NULL);
teken_set_winsize(&teken, &tp);
a = teken_get_defattr(&teken);
snprintf(env, sizeof(env), "%d", a->ta_fgcolor);
env_setenv("teken.fg_color", EV_VOLATILE, env, vidc_set_colors,
env_nounset);
snprintf(env, sizeof(env), "%d", a->ta_bgcolor);
env_setenv("teken.bg_color", EV_VOLATILE, env, vidc_set_colors,
env_nounset);
/* Erase display, this will also fill our screen buffer. */
teken_input(&teken, "\e[J", 3);
for (int i = 0; i < 10 && vidc_ischar(); i++) for (int i = 0; i < 10 && vidc_ischar(); i++)
(void) vidc_getchar(); (void) vidc_getchar();
@ -734,8 +1043,8 @@ vidc_putchar(int c)
{ {
unsigned char ch = c; unsigned char ch = c;
if (buffer != NULL) if (screen_buffer != NULL)
teken_input(&teken, &ch, sizeof (ch)); teken_input(&gfx_state.tg_teken, &ch, sizeof (ch));
else else
vidc_biosputchar(c); vidc_biosputchar(c);
} }

View File

@ -23,7 +23,13 @@ VERSION_FILE= ${.CURDIR}/../loader/version
.PATH: ${BOOTSRC}/i386/loader .PATH: ${BOOTSRC}/i386/loader
# architecture-specific loader code # architecture-specific loader code
SRCS= main.c conf.c vers.c chain.c SRCS= main.c conf.c vers.c chain.c gfx_fb.c 8x16.c
CFLAGS.gfx_fb.c += -I${.CURDIR}/../libi386
CFLAGS.gfx_fb.c += -I$(SRCTOP)/sys/teken
CFLAGS.gfx_fb.c += -I${SRCTOP}/sys/cddl/contrib/opensolaris/common/lz4
CFLAGS.gfx_fb.c += -I${SRCTOP}/contrib/pnglite
CFLAGS.gfx_fb.c += -DHAVE_MEMCPY -I${SRCTOP}/sys/contrib/zlib
# Include bcache code. # Include bcache code.
HAVE_BCACHE= yes HAVE_BCACHE= yes
@ -49,7 +55,7 @@ HELP_FILES= ${.CURDIR}/help.i386
# Always add MI sources # Always add MI sources
.include "${BOOTSRC}/loader.mk" .include "${BOOTSRC}/loader.mk"
CLEANFILES+= ${LOADER} ${LOADER}.bin CLEANFILES+= ${LOADER} ${LOADER}.bin 8x16.c
ORG= 0x0 ORG= 0x0
@ -64,6 +70,9 @@ CFLAGS+= -I${BOOTSRC}/i386
#CFLAGS+= -g #CFLAGS+= -g
#LDFLAGS+= -g #LDFLAGS+= -g
8x16.c: ${SRCTOP}/contrib/terminus/ter-u16v.bdf
vtfontcvt -f compressed-source -o ${.TARGET} ${.ALLSRC}
${LOADER}: ${LOADER}.bin ${BTXLDR} ${BTXKERN} ${LOADER}: ${LOADER}.bin ${BTXLDR} ${BTXKERN}
btxld -v -f aout -e ${LOADER_ADDRESS} -o ${.TARGET} -l ${BTXLDR} \ btxld -v -f aout -e ${LOADER_ADDRESS} -o ${.TARGET} -l ${BTXLDR} \
-b ${BTXKERN} ${LOADER}.bin -b ${BTXKERN} ${LOADER}.bin

View File

@ -130,6 +130,12 @@ main(void)
} }
setheap(heap_bottom, heap_top); setheap(heap_bottom, heap_top);
/*
* detect ACPI for future reference. This may set console to comconsole
* if we do have ACPI SPCR table.
*/
biosacpi_detect();
/* /*
* XXX Chicken-and-egg problem; we want to have console output early, * XXX Chicken-and-egg problem; we want to have console output early,
* but some console attributes may depend on reading from eg. the boot * but some console attributes may depend on reading from eg. the boot
@ -242,9 +248,6 @@ main(void)
initial_bootinfo->bi_extmem = bios_extmem / 1024; initial_bootinfo->bi_extmem = bios_extmem / 1024;
} }
/* detect ACPI for future reference */
biosacpi_detect();
/* detect SMBIOS for future reference */ /* detect SMBIOS for future reference */
smbios_detect(NULL); smbios_detect(NULL);
@ -254,6 +257,7 @@ main(void)
printf("\n%s", bootprog_info); printf("\n%s", bootprog_info);
extract_currdev(); /* set $currdev and $loaddev */ extract_currdev(); /* set $currdev and $loaddev */
autoload_font(true);
bios_getsmap(); bios_getsmap();

9
stand/images/Makefile Normal file
View File

@ -0,0 +1,9 @@
# $FreeBSD$
.include <bsd.init.mk>
FILES+= freebsd-brand-rev.png freebsd-brand.png freebsd-logo-rev.png
FILESDIR= /boot/images
.include <bsd.prog.mk>

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

View File

@ -35,6 +35,8 @@ CFLAGS+= -ffreestanding -nostdlib -DLUA_USE_POSIX
CFLAGS+= -fno-stack-protector -D__BSD_VISIBLE CFLAGS+= -fno-stack-protector -D__BSD_VISIBLE
CFLAGS+= -I${BOOTSRC}/include -I${LIBLUASRC} -I${LUASRC} -I${LDRSRC} CFLAGS+= -I${BOOTSRC}/include -I${LIBLUASRC} -I${LUASRC} -I${LDRSRC}
CFLAGS.lutils.c+= -I${SRCTOP}/sys/teken -I${SRCTOP}/contrib/pnglite
.if ${MACHINE_CPUARCH} == "amd64" && ${DO32:U0} == 0 .if ${MACHINE_CPUARCH} == "amd64" && ${DO32:U0} == 0
CFLAGS+= -fPIC CFLAGS+= -fPIC
.endif .endif

View File

@ -35,6 +35,8 @@ __FBSDID("$FreeBSD$");
#include "lstd.h" #include "lstd.h"
#include "lutils.h" #include "lutils.h"
#include "bootstrap.h" #include "bootstrap.h"
#include <gfx_fb.h>
#include <pnglite.h>
/* /*
* Like loader.perform, except args are passed already parsed * Like loader.perform, except args are passed already parsed
@ -346,6 +348,189 @@ lua_writefile(lua_State *L)
return 1; return 1;
} }
/*
* put image using terminal coordinates.
*/
static int
lua_term_putimage(lua_State *L)
{
const char *name;
png_t png;
uint32_t x1, y1, x2, y2, f;
int nargs, ret = 0, error;
nargs = lua_gettop(L);
if (nargs != 6) {
lua_pushboolean(L, 0);
return 1;
}
name = luaL_checkstring(L, 1);
x1 = luaL_checknumber(L, 2);
y1 = luaL_checknumber(L, 3);
x2 = luaL_checknumber(L, 4);
y2 = luaL_checknumber(L, 5);
f = luaL_checknumber(L, 6);
x1 = gfx_state.tg_origin.tp_col + x1 * gfx_state.tg_font.vf_width;
y1 = gfx_state.tg_origin.tp_row + y1 * gfx_state.tg_font.vf_height;
if (x2 != 0) {
x2 = gfx_state.tg_origin.tp_col +
x2 * gfx_state.tg_font.vf_width;
}
if (y2 != 0) {
y2 = gfx_state.tg_origin.tp_row +
y2 * gfx_state.tg_font.vf_height;
}
if ((error = png_open(&png, name)) != PNG_NO_ERROR) {
if (f & FL_PUTIMAGE_DEBUG)
printf("%s\n", png_error_string(error));
} else {
if (gfx_fb_putimage(&png, x1, y1, x2, y2, f) == 0)
ret = 1;
(void) png_close(&png);
}
lua_pushboolean(L, ret);
return 1;
}
static int
lua_fb_putimage(lua_State *L)
{
const char *name;
png_t png;
uint32_t x1, y1, x2, y2, f;
int nargs, ret = 0, error;
nargs = lua_gettop(L);
if (nargs != 6) {
lua_pushboolean(L, 0);
return 1;
}
name = luaL_checkstring(L, 1);
x1 = luaL_checknumber(L, 2);
y1 = luaL_checknumber(L, 3);
x2 = luaL_checknumber(L, 4);
y2 = luaL_checknumber(L, 5);
f = luaL_checknumber(L, 6);
if ((error = png_open(&png, name)) != PNG_NO_ERROR) {
if (f & FL_PUTIMAGE_DEBUG)
printf("%s\n", png_error_string(error));
} else {
if (gfx_fb_putimage(&png, x1, y1, x2, y2, f) == 0)
ret = 1;
(void) png_close(&png);
}
lua_pushboolean(L, ret);
return 1;
}
static int
lua_fb_setpixel(lua_State *L)
{
uint32_t x, y;
int nargs;
nargs = lua_gettop(L);
if (nargs != 2) {
lua_pushnil(L);
return 1;
}
x = luaL_checknumber(L, 1);
y = luaL_checknumber(L, 2);
gfx_fb_setpixel(x, y);
return 0;
}
static int
lua_fb_line(lua_State *L)
{
uint32_t x0, y0, x1, y1, wd;
int nargs;
nargs = lua_gettop(L);
if (nargs != 5) {
lua_pushnil(L);
return 1;
}
x0 = luaL_checknumber(L, 1);
y0 = luaL_checknumber(L, 2);
x1 = luaL_checknumber(L, 3);
y1 = luaL_checknumber(L, 4);
wd = luaL_checknumber(L, 5);
gfx_fb_line(x0, y0, x1, y1, wd);
return 0;
}
static int
lua_fb_bezier(lua_State *L)
{
uint32_t x0, y0, x1, y1, x2, y2, width;
int nargs;
nargs = lua_gettop(L);
if (nargs != 7) {
lua_pushnil(L);
return 1;
}
x0 = luaL_checknumber(L, 1);
y0 = luaL_checknumber(L, 2);
x1 = luaL_checknumber(L, 3);
y1 = luaL_checknumber(L, 4);
x2 = luaL_checknumber(L, 5);
y2 = luaL_checknumber(L, 6);
width = luaL_checknumber(L, 7);
gfx_fb_bezier(x0, y0, x1, y1, x2, y2, width);
return 0;
}
static int
lua_fb_drawrect(lua_State *L)
{
uint32_t x0, y0, x1, y1, fill;
int nargs;
nargs = lua_gettop(L);
if (nargs != 5) {
lua_pushnil(L);
return 1;
}
x0 = luaL_checknumber(L, 1);
y0 = luaL_checknumber(L, 2);
x1 = luaL_checknumber(L, 3);
y1 = luaL_checknumber(L, 4);
fill = luaL_checknumber(L, 5);
gfx_fb_drawrect(x0, y0, x1, y1, fill);
return 0;
}
static int
lua_term_drawrect(lua_State *L)
{
uint32_t x0, y0, x1, y1;
int nargs;
nargs = lua_gettop(L);
if (nargs != 4) {
lua_pushnil(L);
return 1;
}
x0 = luaL_checknumber(L, 1);
y0 = luaL_checknumber(L, 2);
x1 = luaL_checknumber(L, 3);
y1 = luaL_checknumber(L, 4);
gfx_term_drawrect(x0, y0, x1, y1);
return 0;
}
#define REG_SIMPLE(n) { #n, lua_ ## n } #define REG_SIMPLE(n) { #n, lua_ ## n }
static const struct luaL_Reg loaderlib[] = { static const struct luaL_Reg loaderlib[] = {
REG_SIMPLE(delay), REG_SIMPLE(delay),
@ -360,6 +545,13 @@ static const struct luaL_Reg loaderlib[] = {
REG_SIMPLE(setenv), REG_SIMPLE(setenv),
REG_SIMPLE(time), REG_SIMPLE(time),
REG_SIMPLE(unsetenv), REG_SIMPLE(unsetenv),
REG_SIMPLE(fb_bezier),
REG_SIMPLE(fb_drawrect),
REG_SIMPLE(fb_line),
REG_SIMPLE(fb_putimage),
REG_SIMPLE(fb_setpixel),
REG_SIMPLE(term_drawrect),
REG_SIMPLE(term_putimage),
{ NULL, NULL }, { NULL, NULL },
}; };

View File

@ -8,9 +8,15 @@ SRCS+= boot.c commands.c console.c devopen.c interp.c
SRCS+= interp_backslash.c interp_parse.c ls.c misc.c SRCS+= interp_backslash.c interp_parse.c ls.c misc.c
SRCS+= module.c nvstore.c SRCS+= module.c nvstore.c
CFLAGS.module.c += -I$(SRCTOP)/sys/teken -I${SRCTOP}/contrib/pnglite
.if ${MACHINE} == "i386" || ${MACHINE_CPUARCH} == "amd64" .if ${MACHINE} == "i386" || ${MACHINE_CPUARCH} == "amd64"
SRCS+= load_elf32.c load_elf32_obj.c reloc_elf32.c SRCS+= load_elf32.c load_elf32_obj.c reloc_elf32.c
SRCS+= load_elf64.c load_elf64_obj.c reloc_elf64.c SRCS+= load_elf64.c load_elf64_obj.c reloc_elf64.c
SRCS+= pnglite.c
.PATH: ${SRCTOP}/contrib/pnglite
CFLAGS.pnglite.c+= -I${SRCTOP}/contrib/pnglite
CFLAGS.pnglite.c+= -DHAVE_MEMCPY -I${SRCTOP}/sys/contrib/zlib
.elif ${MACHINE_CPUARCH} == "aarch64" .elif ${MACHINE_CPUARCH} == "aarch64"
SRCS+= load_elf64.c reloc_elf64.c SRCS+= load_elf64.c reloc_elf64.c
.elif ${MACHINE_CPUARCH} == "arm" .elif ${MACHINE_CPUARCH} == "arm"

View File

@ -56,7 +56,7 @@ function color.isEnabled()
if c ~= nil then if c ~= nil then
return c:lower() ~= "no" and c ~= "0" return c:lower() ~= "no" and c ~= "0"
end end
return not core.isSerialBoot() return true
end end
function color.escapefg(color_value) function color.escapefg(color_value)

View File

@ -383,6 +383,19 @@ function core.isZFSBoot()
return false return false
end end
function core.isFramebufferConsole()
local c = loader.getenv("console")
if c ~= nil then
if c:find("efi") == nil and c:find("vidconsole") == nil then
return false
end
if loader.getenv("screen.depth") ~= nil then
return true
end
end
return false
end
function core.isSerialConsole() function core.isSerialConsole()
local c = loader.getenv("console") local c = loader.getenv("console")
if c ~= nil then if c ~= nil then

View File

@ -202,7 +202,7 @@ local function defaultframe()
return "double" return "double"
end end
local function drawbox() local function drawframe()
local x = menu_position.x - 3 local x = menu_position.x - 3
local y = menu_position.y - 1 local y = menu_position.y - 1
local w = frame_size.w local w = frame_size.w
@ -213,7 +213,7 @@ local function drawbox()
-- If we don't have a framespec for the current frame style, just don't -- If we don't have a framespec for the current frame style, just don't
-- draw a box. -- draw a box.
if framespec == nil then if framespec == nil then
return return false
end end
local hl = framespec.horizontal local hl = framespec.horizontal
@ -227,6 +227,11 @@ local function drawbox()
x = x + shift.x x = x + shift.x
y = y + shift.y y = y + shift.y
if core.isFramebufferConsole() and loader.term_drawrect ~= nil then
loader.term_drawrect(x, y, x + w, y + h)
return true
end
screen.setcursor(x, y); printc(tl) screen.setcursor(x, y); printc(tl)
screen.setcursor(x, y + h); printc(bl) screen.setcursor(x, y + h); printc(bl)
screen.setcursor(x + w, y); printc(tr) screen.setcursor(x + w, y); printc(tr)
@ -248,12 +253,25 @@ local function drawbox()
screen.setcursor(x + w, y + i) screen.setcursor(x + w, y + i)
printc(vl) printc(vl)
end end
return true
end
local function drawbox()
local x = menu_position.x - 3
local y = menu_position.y - 1
local w = frame_size.w
local menu_header = loader.getenv("loader_menu_title") or local menu_header = loader.getenv("loader_menu_title") or
"Welcome to FreeBSD" "Welcome to FreeBSD"
local menu_header_align = loader.getenv("loader_menu_title_align") local menu_header_align = loader.getenv("loader_menu_title_align")
local menu_header_x local menu_header_x
x = x + shift.x
y = y + shift.y
if drawframe(x, y, w) == false then
return
end
if menu_header_align ~= nil then if menu_header_align ~= nil then
menu_header_align = menu_header_align:lower() menu_header_align = menu_header_align:lower()
if menu_header_align == "left" then if menu_header_align == "left" then
@ -287,6 +305,14 @@ local function drawbrand()
x = x + shift.x x = x + shift.x
y = y + shift.y y = y + shift.y
if core.isFramebufferConsole() and
loader.term_putimage ~= nil and
branddef.image ~= nil then
if loader.term_putimage(branddef.image, 0, 0, 0, 7, 0)
then
return true
end
end
draw(x, y, graphic) draw(x, y, graphic)
end end
@ -330,9 +356,33 @@ local function drawlogo()
y = y + logodef.shift.y y = y + logodef.shift.y
end end
if core.isFramebufferConsole() and
loader.term_putimage ~= nil and
logodef.image ~= nil then
local y1 = 15
if logodef.image_rl ~= nil then
y1 = logodef.image_rl
end
if loader.term_putimage(logodef.image, x, y, 0, y + y1, 0)
then
return true
end
end
draw(x, y, logodef.graphic) draw(x, y, logodef.graphic)
end end
local function drawitem(func)
local console = loader.getenv("console")
local c
for c in string.gmatch(console, "%w+") do
loader.setenv("console", c)
func()
end
loader.setenv("console", console)
end
fbsd_brand = { fbsd_brand = {
" ______ ____ _____ _____ ", " ______ ____ _____ _____ ",
" | ____| | _ \\ / ____| __ \\ ", " | ____| | _ \\ / ____| __ \\ ",
@ -378,6 +428,7 @@ branddefs = {
-- keys are: graphic (table depicting graphic) -- keys are: graphic (table depicting graphic)
["fbsd"] = { ["fbsd"] = {
graphic = fbsd_brand, graphic = fbsd_brand,
image = "/boot/images/freebsd-brand-rev.png",
}, },
["none"] = { ["none"] = {
graphic = none, graphic = none,
@ -458,9 +509,9 @@ drawer.frame_styles = {
function drawer.drawscreen(menudef) function drawer.drawscreen(menudef)
-- drawlogo() must go first. -- drawlogo() must go first.
-- it determines the positions of other elements -- it determines the positions of other elements
drawlogo() drawitem(drawlogo)
drawbrand() drawitem(drawbrand)
drawbox() drawitem(drawbox)
return drawmenu(menudef) return drawmenu(menudef)
end end

View File

@ -47,6 +47,8 @@ return {
" .---.....----.\027[m", " .---.....----.\027[m",
}, },
requires_color = true, requires_color = true,
shift = {x = 2, y = 4}, shift = {x = 2, y = 3},
image = "/boot/images/freebsd-logo-rev.png",
image_rl = 15
} }
} }

View File

@ -35,6 +35,7 @@ CFLAGS+= -I${BOOTSRC}/userboot
CFLAGS.main.c+= -I${BOOTSRC}/libsa/zfs CFLAGS.main.c+= -I${BOOTSRC}/libsa/zfs
CFLAGS.main.c+= -I${SYSDIR}/contrib/openzfs/include CFLAGS.main.c+= -I${SYSDIR}/contrib/openzfs/include
CFLAGS.main.c+= -I${SYSDIR}/contrib/openzfs/include/os/freebsd/zfs CFLAGS.main.c+= -I${SYSDIR}/contrib/openzfs/include/os/freebsd/zfs
CFLAGS.userboot_cons.c+= -I$(SRCTOP)/sys/teken -I${SRCTOP}/contrib/pnglite
CWARNFLAGS.main.c += -Wno-implicit-function-declaration CWARNFLAGS.main.c += -Wno-implicit-function-declaration
LDFLAGS+= -nostdlib -Wl,-Bsymbolic LDFLAGS+= -nostdlib -Wl,-Bsymbolic

View File

@ -28,9 +28,14 @@
__FBSDID("$FreeBSD$"); __FBSDID("$FreeBSD$");
#include <stand.h> #include <stand.h>
#include <sys/font.h>
#include "gfx_fb.h"
#include "bootstrap.h" #include "bootstrap.h"
#include "libuserboot.h" #include "libuserboot.h"
font_list_t fonts = STAILQ_HEAD_INITIALIZER(fonts);
teken_gfx_t gfx_state = { 0 };
int console; int console;
static struct console *userboot_comconsp; static struct console *userboot_comconsp;

View File

@ -93,9 +93,10 @@ typedef struct vt_font_bitmap_data {
} vt_font_bitmap_data_t; } vt_font_bitmap_data_t;
typedef enum { typedef enum {
FONT_AUTO, FONT_AUTO, /* This font is loaded by software */
FONT_MANUAL, FONT_MANUAL, /* This font is loaded manually by user */
FONT_BOOT FONT_BUILTIN, /* This font was built in at compile time */
FONT_RELOAD /* This font is marked to be re-read from file */
} FONT_FLAGS; } FONT_FLAGS;
struct fontlist { struct fontlist {

View File

@ -48,6 +48,7 @@ typedef unsigned char teken_format_t;
#define TF_BLINK 0x04 /* Blinking character. */ #define TF_BLINK 0x04 /* Blinking character. */
#define TF_REVERSE 0x08 /* Reverse rendered character. */ #define TF_REVERSE 0x08 /* Reverse rendered character. */
#define TF_CJK_RIGHT 0x10 /* Right-hand side of CJK character. */ #define TF_CJK_RIGHT 0x10 /* Right-hand side of CJK character. */
#define TF_IMAGE 0x20 /* This character space has image. */
typedef unsigned char teken_color_t; typedef unsigned char teken_color_t;
#define TC_BLACK 0 #define TC_BLACK 0
#define TC_RED 1 #define TC_RED 1