diff options
author | Toomas Soome <tsoome@FreeBSD.org> | 2020-12-21 05:31:16 +0000 |
---|---|---|
committer | Toomas Soome <tsoome@FreeBSD.org> | 2021-01-02 19:41:36 +0000 |
commit | 3630506b9daec9167a89bc4525638ea45a00769e (patch) | |
tree | 8276b2e49eeaedbc1fb1806c5a9f64ee642bdc57 /stand/efi | |
parent | bd03acedb804add1e22178d50eb2bfb703974ddf (diff) |
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
Diffstat (limited to 'stand/efi')
-rw-r--r-- | stand/efi/include/efilib.h | 1 | ||||
-rw-r--r-- | stand/efi/libefi/Makefile | 2 | ||||
-rw-r--r-- | stand/efi/libefi/efi_console.c | 484 | ||||
-rw-r--r-- | stand/efi/loader/Makefile | 14 | ||||
-rw-r--r-- | stand/efi/loader/bootinfo.c | 17 | ||||
-rw-r--r-- | stand/efi/loader/framebuffer.c | 15 | ||||
-rw-r--r-- | stand/efi/loader/main.c | 3 |
7 files changed, 361 insertions, 175 deletions
diff --git a/stand/efi/include/efilib.h b/stand/efi/include/efilib.h index 6f1dbac98730..b9b9030afd7f 100644 --- a/stand/efi/include/efilib.h +++ b/stand/efi/include/efilib.h @@ -108,7 +108,6 @@ void efi_time_init(void); void efi_time_fini(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 main(int argc, CHAR16 *argv[]); diff --git a/stand/efi/libefi/Makefile b/stand/efi/libefi/Makefile index 8006893d0cbe..010754b5238a 100644 --- a/stand/efi/libefi/Makefile +++ b/stand/efi/libefi/Makefile @@ -49,7 +49,7 @@ CFLAGS+= -fPIC -mno-red-zone .endif CFLAGS+= -I${EFIINC} 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 .if ${MK_LOADER_ZFS} != "no" CFLAGS+= -I${ZFSSRC} diff --git a/stand/efi/libefi/efi_console.c b/stand/efi/libefi/efi_console.c index a72fb4d561da..22adcd3a00e2 100644 --- a/stand/efi/libefi/efi_console.c +++ b/stand/efi/libefi/efi_console.c @@ -27,17 +27,22 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#include <sys/param.h> #include <efi.h> #include <efilib.h> #include <teken.h> #include <sys/reboot.h> - +#include <machine/metadata.h> +#include <gfx_fb.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 SIMPLE_TEXT_OUTPUT_INTERFACE *conout; static SIMPLE_INPUT_INTERFACE *conin; static EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *coninex; +static bool efi_started; static int mode; /* Does ConOut have serial console? */ @@ -59,6 +64,9 @@ void HO(void); void end_term(void); #endif +#define TEXT_ROWS 24 +#define TEXT_COLS 80 + static tf_bell_t efi_cons_bell; static tf_cursor_t efi_text_cursor; static tf_putchar_t efi_text_putchar; @@ -77,16 +85,16 @@ static teken_funcs_t tf = { .tf_respond = efi_cons_respond, }; -teken_t teken; -teken_pos_t tp; - -struct text_pixel { - teken_char_t c; - teken_attr_t a; +static teken_funcs_t tfx = { + .tf_bell = efi_cons_bell, + .tf_cursor = gfx_fb_cursor, + .tf_putchar = gfx_fb_putchar, + .tf_fill = gfx_fb_fill, + .tf_copy = gfx_fb_copy, + .tf_param = gfx_fb_param, + .tf_respond = efi_cons_respond, }; -static struct text_pixel *buffer; - #define KEYBUFSZ 10 static unsigned keybuf[KEYBUFSZ]; /* keybuf for extended codes */ static int key_pending; @@ -116,6 +124,7 @@ void efi_cons_putchar(int); int efi_cons_getchar(void); void efi_cons_efiputchar(int); int efi_cons_poll(void); +static void cons_draw_frame(teken_attr_t *); struct console efi_console = { "efi", @@ -129,6 +138,28 @@ struct console efi_console = { }; /* + * 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. */ static void @@ -137,33 +168,30 @@ efi_cons_bell(void *s __unused) } 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); + row = p->tp_row; + if (p->tp_row >= state->tg_tp.tp_row) + row = state->tg_tp.tp_row - 1; - 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; + 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); } 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; struct text_pixel *px; 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; 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); - /* to prvent autoscroll, skip print of lower right char */ + /* to prevent autoscroll, skip print of lower right char */ if (!autoscroll && - p->tp_row == tp.tp_row - 1 && - p->tp_col == tp.tp_col - 1) + p->tp_row == state->tg_tp.tp_row - 1 && + p->tp_col == state->tg_tp.tp_col - 1) return; (void) conout->SetAttribute(conout, attr); @@ -196,58 +224,80 @@ efi_text_printchar(const teken_pos_t *p, bool autoscroll) } 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) { + teken_gfx_t *state = s; EFI_STATUS status; int idx; - idx = p->tp_col + p->tp_row * tp.tp_col; - buffer[idx].c = c; - buffer[idx].a = *a; - efi_text_printchar(p, false); + 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].c = c; + screen_buffer[idx].a = *a; + + efi_text_printchar(s, p, false); } 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) { + teken_gfx_t *state = arg; teken_pos_t p; - UINTN row, col; - - (void) conout->QueryMode(conout, conout->Mode->Mode, &col, &row); - conout->EnableCursor(conout, FALSE); + if (state->tg_cursor_visible) + conout->EnableCursor(conout, FALSE); 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++) - efi_text_putchar(s, &p, c, a); - conout->EnableCursor(conout, TRUE); + efi_text_putchar(state, &p, c, a); + if (state->tg_cursor_visible) + conout->EnableCursor(conout, TRUE); } -static bool -efi_same_pixel(struct text_pixel *px1, struct text_pixel *px2) +static void +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) - 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); + unsigned soffset, doffset; + teken_pos_t sp, dp; + int x; + + soffset = s->tp_col + s->tp_row * state->tg_tp.tp_col; + doffset = d->tp_col + d->tp_row * state->tg_tp.tp_col; + + 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 -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; - int nrow, ncol, x, y; /* Has to be signed - >= 0 comparison */ + teken_gfx_t *state = arg; + unsigned doffset, soffset; teken_pos_t d, s; + int nrow, ncol, x, y; /* Has to be signed - >= 0 comparison */ 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. */ 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; - conout->EnableCursor(conout, FALSE); - if (p->tp_row < r->tr_begin.tp_row) { - /* Copy from bottom to top. */ + 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); + + /* + * Copy line by line. + */ + if (doffset <= soffset) { + s = r->tr_begin; + d = *p; 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 - * scroll. - */ - if (y == nrow - 1 && - x == ncol - 1) { - efi_text_printchar(&d, true); - } - } - } + d.tp_row = p->tp_row + y; + + efi_text_copy_line(state, ncol, &s, &d, scroll); } } 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--) { - 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]; - 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; - 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( - &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); - } - } - } + for (y = nrow - 1; y >= 0; 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, false); } } - conout->EnableCursor(conout, TRUE); + + /* display the cursor */ + if (state->tg_cursor_visible) + conout->EnableCursor(conout, TRUE); } 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) { case TP_SETLOCALCURSOR: /* @@ -357,10 +364,13 @@ efi_text_param(void *s __unused, int cmd, unsigned int value) value = (value == 1) ? 0 : 1; /* FALLTHROUGH */ case TP_SHOWCURSOR: - if (value == 1) + if (value != 0) { conout->EnableCursor(conout, TRUE); - else + state->tg_cursor_visible = true; + } else { conout->EnableCursor(conout, FALSE); + state->tg_cursor_visible = false; + } break; default: /* Not yet implemented */ @@ -470,7 +480,7 @@ efi_set_colors(struct env_var *ev, int flags, const void *value) evalue = value; } - ap = teken_get_defattr(&teken); + ap = teken_get_defattr(&gfx_state.tg_teken); a = *ap; if (strcmp(ev->ev_name, "teken.fg_color") == 0) { /* is it already set? */ @@ -484,8 +494,15 @@ efi_set_colors(struct env_var *ev, int flags, const void *value) return (CMD_OK); 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); - teken_set_defattr(&teken, &a); + teken_input(&gfx_state.tg_teken, "\e[2J", 4); return (CMD_OK); } @@ -823,19 +840,100 @@ efi_term_emu(int c) #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 -efi_cons_update_mode(void) +cons_update_mode(bool use_gfx_mode) { UINTN cols, rows; const teken_attr_t *a; teken_attr_t attr; 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); if (EFI_ERROR(status) || cols * rows == 0) { - cols = 80; - rows = 24; + cols = TEXT_COLS; + rows = TEXT_ROWS; } /* @@ -853,20 +951,74 @@ efi_cons_update_mode(void) */ mode = parse_uefi_con_out(); if ((mode & (RB_SERIAL | RB_MULTIPLE)) == 0) { - if (buffer != NULL) { - if (tp.tp_row == rows && tp.tp_col == cols) - return (true); - free(buffer); + conout->EnableCursor(conout, FALSE); + gfx_state.tg_cursor_visible = false; + + 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 { - 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; - tp.tp_col = cols; - buffer = malloc(rows * cols * sizeof(*buffer)); - if (buffer != NULL) { - teken_set_winsize(&teken, &tp); - a = teken_get_defattr(&teken); + /* Record our terminal screen size. */ + gfx_state.tg_tp.tp_row = rows; + gfx_state.tg_tp.tp_col = cols; + + teken_init(&gfx_state.tg_teken, gfx_state.tg_functions, + &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; /* @@ -880,7 +1032,7 @@ efi_cons_update_mode(void) ptr = getenv("teken.bg_color"); attr.ta_bgcolor = strtol(ptr, NULL, 10); - teken_set_defattr(&teken, &attr); + teken_set_defattr(&gfx_state.tg_teken, &attr); } else { snprintf(env, sizeof(env), "%d", attr.ta_fgcolor); @@ -891,18 +1043,12 @@ efi_cons_update_mode(void) env_setenv("teken.bg_color", EV_VOLATILE, env, 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 - if (buffer == NULL) { conout->SetAttribute(conout, EFI_TEXT_ATTR(DEFAULT_FGCOLOR, DEFAULT_BGCOLOR)); end_term(); @@ -910,8 +1056,23 @@ efi_cons_update_mode(void) curs_move(&curx, &cury, curx, cury); fg_c = DEFAULT_FGCOLOR; bg_c = DEFAULT_BGCOLOR; - } #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); setenv("LINES", env, 1); @@ -926,8 +1087,13 @@ efi_cons_init(int arg) { EFI_STATUS status; - conout->EnableCursor(conout, TRUE); - if (efi_cons_update_mode()) + if (efi_started) + return (0); + + efi_started = true; + + gfx_framework_init(); + if (cons_update_mode(gfx_state.tg_fb_type != FB_TEXT)) return (0); 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 * 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); return; } - teken_input(&teken, &ch, sizeof (ch)); + teken_input(&gfx_state.tg_teken, &ch, sizeof (ch)); } static int diff --git a/stand/efi/loader/Makefile b/stand/efi/loader/Makefile index a0e7f95b8200..3cf2df933cc3 100644 --- a/stand/efi/loader/Makefile +++ b/stand/efi/loader/Makefile @@ -22,7 +22,9 @@ SRCS= autoload.c \ framebuffer.c \ main.c \ self_reloc.c \ - vers.c + vers.c \ + gfx_fb.c \ + 8x16.c CFLAGS+= -I${.CURDIR}/../loader .if ${MK_LOADER_ZFS} != "no" @@ -33,6 +35,11 @@ CFLAGS+= -DEFI_ZFS_BOOT HAVE_ZFS= yes .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 # 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 @@ -74,6 +81,11 @@ VERSION_FILE= ${.CURDIR}/../loader/version # Always add MI sources .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 FILESMODE_${LOADER}.efi= ${BINMODE} diff --git a/stand/efi/loader/bootinfo.c b/stand/efi/loader/bootinfo.c index b1df11acd53f..108f46c5f9c4 100644 --- a/stand/efi/loader/bootinfo.c +++ b/stand/efi/loader/bootinfo.c @@ -447,7 +447,7 @@ bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp) */ uint32_t mdt[] = { MODINFOMD_SSYM, MODINFOMD_ESYM, MODINFOMD_KERNEND, - MODINFOMD_ENVP, + MODINFOMD_ENVP, MODINFOMD_FONT, #if defined(LOADER_FDT_SUPPORT) MODINFOMD_DTBP #endif @@ -480,6 +480,11 @@ bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp) /* Pad to a page boundary. */ addr = roundup(addr, PAGE_SIZE); + addr = build_font_module(addr); + + /* Pad to a page boundary. */ + addr = roundup(addr, PAGE_SIZE); + /* Copy our environment. */ envp = addr; addr = bi_copyenv(addr); @@ -503,17 +508,17 @@ bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp) if (kfp == NULL) panic("can't find kernel file"); kernend = 0; /* fill it in later */ - file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); - file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); + file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof(howto), &howto); + file_addmetadata(kfp, MODINFOMD_ENVP, sizeof(envp), &envp); #if defined(LOADER_FDT_SUPPORT) if (dtb_size) - file_addmetadata(kfp, MODINFOMD_DTBP, sizeof dtbp, &dtbp); + file_addmetadata(kfp, MODINFOMD_DTBP, sizeof(dtbp), &dtbp); else printf("WARNING! Trying to fire up the kernel, but no " "device tree blob found!\n"); #endif - file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); - file_addmetadata(kfp, MODINFOMD_FW_HANDLE, sizeof ST, &ST); + file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof(kernend), &kernend); + file_addmetadata(kfp, MODINFOMD_FW_HANDLE, sizeof(ST), &ST); #ifdef LOADER_GELI_SUPPORT geli_export_key_metadata(kfp); #endif diff --git a/stand/efi/loader/framebuffer.c b/stand/efi/loader/framebuffer.c index dce49c69ab0e..fccbd82a09f7 100644 --- a/stand/efi/loader/framebuffer.c +++ b/stand/efi/loader/framebuffer.c @@ -40,9 +40,10 @@ __FBSDID("$FreeBSD$"); #include <efipciio.h> #include <machine/metadata.h> +#include "bootstrap.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 uga_guid = EFI_UGA_DRAW_PROTOCOL_GUID; @@ -586,7 +587,7 @@ gop_autoresize(EFI_GRAPHICS_OUTPUT *gop) mode, EFI_ERROR_CODE(status)); return (CMD_ERROR); } - (void) efi_cons_update_mode(); + (void) cons_update_mode(true); } return (CMD_OK); } @@ -611,7 +612,7 @@ text_autoresize() } if (max_dim > 0) conout->SetMode(conout, best_mode); - (void) efi_cons_update_mode(); + (void) cons_update_mode(true); return (CMD_OK); } @@ -699,8 +700,10 @@ command_gop(int argc, char *argv[]) argv[0], mode, EFI_ERROR_CODE(status)); return (CMD_ERROR); } - (void) efi_cons_update_mode(); - } else if (!strcmp(argv[1], "get")) { + (void) cons_update_mode(true); + } else if (strcmp(argv[1], "off") == 0) { + (void) cons_update_mode(false); + } else if (strcmp(argv[1], "get") == 0) { if (argc != 2) goto usage; efifb_from_gop(&efifb, gop->Mode, gop->Mode->Info); @@ -728,7 +731,7 @@ command_gop(int argc, char *argv[]) usage: 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); } diff --git a/stand/efi/loader/main.c b/stand/efi/loader/main.c index aad285f59092..ca41cd4a2610 100644 --- a/stand/efi/loader/main.c +++ b/stand/efi/loader/main.c @@ -1155,6 +1155,7 @@ main(int argc, CHAR16 *argv[]) !interactive_interrupt("Failed to find bootable partition")) return (EFI_NOT_FOUND); + autoload_font(false); /* Set up the font list for console. */ efi_init_environment(); #if !defined(__arm__) @@ -1354,7 +1355,7 @@ command_mode(int argc, char *argv[]) printf("couldn't set mode %d\n", mode); return (CMD_ERROR); } - (void) efi_cons_update_mode(); + (void) cons_update_mode(true); return (CMD_OK); } |