Print this page
NEX-16819 loader UEFI support
Includes work by Toomas Soome <tsoome@me.com>
Upstream commits:
    loader: pxe receive cleanup
    9475 libefi: Do not return only if ReceiveFilter
    installboot: should support efi system partition
    8931 boot1.efi: scan all display modes rather than
    loader: spinconsole updates
    loader: gfx experiment to try GOP Blt() function.
    sha1 build test
    loader: add sha1 hash calculation
    common/sha1: update for loader build
    loader: biosdisk rework
    uts: 32-bit kernel FB needs mapping in low memory
    uts: add diag-device
    uts: boot console mirror with diag-device
    uts: enable very early console on ttya
    kmdb: add diag-device as input/output device
    uts: test VGA memory exclusion from mapping
    uts: clear boot mapping and protect boot pages test
    uts: add dboot map debug printf
    uts: need to release FB pages in release_bootstrap()
    uts: add screenmap ioctl
    uts: update sys/queue.h
    loader: add illumos uts/common to include path
    loader: tem/gfx font cleanup
    loader: vbe checks
    uts: gfx_private set KD_TEXT when KD_RESETTEXT is
    uts: gfx 8-bit update
    loader: gfx 8-bit fix
    loader: always set media size from partition.
    uts: MB2 support for 32-bit kernel
    loader: x86 should have tem 80x25
    uts: x86 should have tem 80x25
    uts: font update
    loader: font update
    uts: tem attributes
    loader: tem.c comment added
    uts: use font module
    loader: add font module
    loader: build rules for new font setup
    uts: gfx_private update for new font structure
    uts: early boot update for new font structure
    uts: font update
    uts: font build rules update for new fonts
    uts: tem update to new font structure
    loader: module.c needs to include tem_impl.h
    uts: gfx_private 8x16 font rework
    uts: make font_lookup public
    loader: font rework
    uts: font rework
    9259 libefi: efi_alloc_and_read should check for PMBR
    uts: tem utf-8 support
    loader: implement tem utf-8 support
    loader: tem should be able to display UTF-8
    7784 uts: console input should support utf-8
    7796 uts: ldterm default to utf-8
    uts: do not reset serial console
    uts: set up colors even if tem is not console
    uts: add type for early boot properties
    uts: gfx_private experiment with drm and vga
    uts: gfx_private should use setmode drm callback.
    uts: identify FB types and set up gfx_private based
    loader: replace gop and vesa with framebuffer
    uts: boot needs simple tem to support mdb
    uts: boot_keyboard should emit esc sequences for
    uts: gfx_private FB showuld be written by line
    kmdb: set terminal window size
    uts: gfx_private needs to keep track of early boot FB
    pnglite: move pnglite to usr/src/common
    loader: gfx_fb
    ficl-sys: add gfx primitives
    loader: add illumos.png logo
    ficl: add fb-putimage
    loader: add png support
    loader: add alpha blending for gfx_fb
    loader: use term-drawrect for menu frame
    ficl: add simple gfx words
    uts: provide fb_info via fbgattr dev_specific array.
    uts: gfx_private add alpha blending
    uts: update sys/ascii.h
    uts: tem OSC support (incomplete)
    uts: implement env module support and use data from
    uts: tem get colors from early boot data
    loader: use crc32 from libstand (libz)
    loader: optimize for size
    loader: pass tem info to the environment
    loader: import tem for loader console
    loader: UEFI loader needs to set ISADIR based on
    loader: need UEFI32 support
    8918 loader.efi: add vesa edid support
    uts: tem_safe_pix_clear_prom_output() should only
    uts: tem_safe_pix_clear_entire_screen() should use
    uts: tem_safe_check_first_time() should query cursor
    uts: tem implement cls callback & visual_io v4
    uts: gfx_vgatext use block cursor for vgatext
    uts: gfx_private implement cls callback & visual_io
    uts: gfx_private bitmap framebuffer implementation
    uts: early start frame buffer console support
    uts: font functions should check the input char
    uts: font rendering should support 16/24/32bit depths
    uts: use smallest font as fallback default.
    uts: update terminal dimensions based on selected
    7834 uts: vgatext should use gfx_private
    uts: add spacing property to 8859-1.bdf
    terminfo: add underline for sun-color
    terminfo: sun-color has 16 colors
    uts: add font load callback type
    loader: do not repeat int13 calls with error 0x20 and
    8905 loader: add skein/edonr support
    8904 common/crypto: make skein and edonr loader
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Revert "NEX-16819 loader UEFI support"
This reverts commit ec06b9fc617b99234e538bf2e7e4d02a24993e0c.
Reverting due to failures in the zfs-tests and the sharefs-tests
NEX-16819 loader UEFI support
Includes work by Toomas Soome <tsoome@me.com>
Upstream commits:
    loader: pxe receive cleanup
    9475 libefi: Do not return only if ReceiveFilter
    installboot: should support efi system partition
    8931 boot1.efi: scan all display modes rather than
    loader: spinconsole updates
    loader: gfx experiment to try GOP Blt() function.
    sha1 build test
    loader: add sha1 hash calculation
    common/sha1: update for loader build
    loader: biosdisk rework
    uts: 32-bit kernel FB needs mapping in low memory
    uts: add diag-device
    uts: boot console mirror with diag-device
    uts: enable very early console on ttya
    kmdb: add diag-device as input/output device
    uts: test VGA memory exclusion from mapping
    uts: clear boot mapping and protect boot pages test
    uts: add dboot map debug printf
    uts: need to release FB pages in release_bootstrap()
    uts: add screenmap ioctl
    uts: update sys/queue.h
    loader: add illumos uts/common to include path
    loader: tem/gfx font cleanup
    loader: vbe checks
    uts: gfx_private set KD_TEXT when KD_RESETTEXT is
    uts: gfx 8-bit update
    loader: gfx 8-bit fix
    loader: always set media size from partition.
    uts: MB2 support for 32-bit kernel
    loader: x86 should have tem 80x25
    uts: x86 should have tem 80x25
    uts: font update
    loader: font update
    uts: tem attributes
    loader: tem.c comment added
    uts: use font module
    loader: add font module
    loader: build rules for new font setup
    uts: gfx_private update for new font structure
    uts: early boot update for new font structure
    uts: font update
    uts: font build rules update for new fonts
    uts: tem update to new font structure
    loader: module.c needs to include tem_impl.h
    uts: gfx_private 8x16 font rework
    uts: make font_lookup public
    loader: font rework
    uts: font rework
    libefi: efi_alloc_and_read should check for PMBR
    uts: tem utf-8 support
    loader: implement tem utf-8 support
    loader: tem should be able to display UTF-8
    7784 uts: console input should support utf-8
    7796 uts: ldterm default to utf-8
    uts: do not reset serial console
    uts: set up colors even if tem is not console
    uts: add type for early boot properties
    uts: gfx_private experiment with drm and vga
    uts: gfx_private should use setmode drm callback.
    uts: identify FB types and set up gfx_private based
    loader: replace gop and vesa with framebuffer
    uts: boot needs simple tem to support mdb
    uts: boot_keyboard should emit esc sequences for
    uts: gfx_private FB showuld be written by line
    kmdb: set terminal window size
    uts: gfx_private needs to keep track of early boot FB
    pnglite: move pnglite to usr/src/common
    loader: gfx_fb
    ficl-sys: add gfx primitives
    loader: add illumos.png logo
    ficl: add fb-putimage
    loader: add png support
    loader: add alpha blending for gfx_fb
    loader: use term-drawrect for menu frame
    ficl: add simple gfx words
    uts: provide fb_info via fbgattr dev_specific array.
    uts: gfx_private add alpha blending
    uts: update sys/ascii.h
    uts: tem OSC support (incomplete)
    uts: implement env module support and use data from
    uts: tem get colors from early boot data
    loader: use crc32 from libstand (libz)
    loader: optimize for size
    loader: pass tem info to the environment
    loader: import tem for loader console
    loader: UEFI loader needs to set ISADIR based on
    loader: need UEFI32 support
    8918 loader.efi: add vesa edid support
    uts: tem_safe_pix_clear_prom_output() should only
    uts: tem_safe_pix_clear_entire_screen() should use
    uts: tem_safe_check_first_time() should query cursor
    uts: tem implement cls callback & visual_io v4
    uts: gfx_vgatext use block cursor for vgatext
    uts: gfx_private implement cls callback & visual_io
    uts: gfx_private bitmap framebuffer implementation
    uts: early start frame buffer console support
    uts: font functions should check the input char
    uts: font rendering should support 16/24/32bit depths
    uts: use smallest font as fallback default.
    uts: update terminal dimensions based on selected
    7834 uts: vgatext should use gfx_private
    uts: add spacing property to 8859-1.bdf
    terminfo: add underline for sun-color
    terminfo: sun-color has 16 colors
    uts: add font load callback type
    loader: do not repeat int13 calls with error 0x20 and
    8905 loader: add skein/edonr support
    8904 common/crypto: make skein and edonr loader
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>

*** 32,45 **** --- 32,80 ---- * Generic font related data and functions shared by early boot console * in dboot, kernel startup and full kernel. */ #include <sys/types.h> #include <sys/systm.h> + #include <sys/tem_impl.h> #include <sys/font.h> #include <sys/sysmacros.h> /* + * To simplify my life, I am "temporarily" collecting the commonly used + * color bits here. The bits shared between loader, dboot, early boot, tem. + * This data would need some sort of API, but I am in no condition to figure + * something out right now. + */ + + /* ANSI color to sun color translation. */ + /* BEGIN CSTYLED */ + /* Bk Rd Gr Br Bl Mg Cy Wh */ + const uint8_t dim_xlate[] = { 1, 5, 3, 7, 2, 6, 4, 8 }; + const uint8_t brt_xlate[] = { 9, 13, 11, 15, 10, 14, 12, 0 }; + + /* The pc color here is actually referring to standard 16 color VGA map. */ + const uint8_t solaris_color_to_pc_color[16] = { + 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 + }; + + /* 4-bit to 24-bit color translation. */ + const text_cmap_t cmap4_to_24 = { + /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + Wh+ Bk Bl Gr Cy Rd Mg Br Wh Bk+ Bl+ Gr+ Cy+ Rd+ Mg+ Yw */ + .red = { + 0xff,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x40,0x00,0x00,0x00,0xff,0xff,0xff + }, + .green = { + 0xff,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x80,0x40,0x00,0xff,0xff,0x00,0x00,0xff + }, + .blue = { + 0xff,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x40,0xff,0x00,0xff,0x00,0xff,0x00 + } + }; + /* END CSTYLED */ + + /* * Fonts are statically linked with this module. At some point an * RFE might be desireable to allow dynamic font loading. The * original intention to facilitate dynamic fonts can be seen * by examining the data structures and set_font(). As much of * the original code is retained but modified to be suited for
*** 47,112 **** */ /* * Must be sorted by font size in descending order */ ! struct fontlist fonts[] = { ! { &font_data_12x22, NULL }, ! { &font_data_8x16, NULL }, ! { &font_data_7x14, NULL }, ! { &font_data_6x10, NULL }, ! { NULL, NULL } ! }; ! void ! set_font(struct font *f, short *rows, short *cols, short height, short width) { ! bitmap_data_t *font_selected = NULL; struct fontlist *fl; - int i; /* * Find best font for these dimensions, or use default * * A 1 pixel border is the absolute minimum we could have * as a border around the text window (BORDER_PIXELS = 2), * however a slightly larger border not only looks better * but for the fonts currently statically built into the * emulator causes much better font selection for the * normal range of screen resolutions. */ ! for (fl = fonts; fl->data; fl++) { ! if ((((*rows * fl->data->height) + BORDER_PIXELS) <= height) && ! (((*cols * fl->data->width) + BORDER_PIXELS) <= width)) { ! font_selected = fl->data; break; } } /* ! * The minus 2 is to make sure we have at least a 1 pixel ! * border around the entire screen. */ ! if (font_selected == NULL) { ! if (((*rows * DEFAULT_FONT_DATA.height) > height) || ! ((*cols * DEFAULT_FONT_DATA.width) > width)) { ! *rows = (height - 2) / DEFAULT_FONT_DATA.height; ! *cols = (width - 2) / DEFAULT_FONT_DATA.width; } ! font_selected = &DEFAULT_FONT_DATA; } ! f->width = font_selected->width; ! f->height = font_selected->height; ! for (i = 0; i < ENCODED_CHARS; i++) ! f->char_ptr[i] = font_selected->encoding[i]; ! f->image_data = font_selected->image; } /* * bit_to_pix4 is for 4-bit frame buffers. It will write one output byte * for each 2 bits of input bitmap. It inverts the input bits before * doing the output translation, for reverse video. * * Assuming foreground is 0001 and background is 0000... --- 82,236 ---- */ /* * Must be sorted by font size in descending order */ ! font_list_t fonts = STAILQ_HEAD_INITIALIZER(fonts); ! bitmap_data_t * ! set_font(short *rows, short *cols, short height, short width) { ! bitmap_data_t *font = NULL; struct fontlist *fl; /* + * First check for manually loaded font. + */ + STAILQ_FOREACH(fl, &fonts, font_next) { + if (fl->font_flags == FONT_MANUAL || + fl->font_flags == FONT_BOOT) { + font = fl->font_data; + if (font->font == NULL && fl->font_load != NULL && + fl->font_name != NULL) { + font = fl->font_load(fl->font_name); + } + if (font == NULL || font->font == NULL) + font = NULL; + break; + } + } + + if (font != NULL) { + *rows = (height - BORDER_PIXELS) / font->height; + *cols = (width - BORDER_PIXELS) / font->width; + return (font); + } + + /* * Find best font for these dimensions, or use default * * A 1 pixel border is the absolute minimum we could have * as a border around the text window (BORDER_PIXELS = 2), * however a slightly larger border not only looks better * but for the fonts currently statically built into the * emulator causes much better font selection for the * normal range of screen resolutions. */ ! STAILQ_FOREACH(fl, &fonts, font_next) { ! font = fl->font_data; ! if ((((*rows * font->height) + BORDER_PIXELS) <= height) && ! (((*cols * font->width) + BORDER_PIXELS) <= width)) { ! if (font->font == NULL) { ! if (fl->font_load != NULL && ! fl->font_name != NULL) { ! font = fl->font_load(fl->font_name); ! } ! if (font == NULL) ! continue; ! } ! *rows = (height - BORDER_PIXELS) / font->height; ! *cols = (width - BORDER_PIXELS) / font->width; break; } + font = NULL; } + + if (font == NULL) { /* ! * We have fonts sorted smallest last, try it before ! * falling back to builtin. */ ! fl = STAILQ_LAST(&fonts, fontlist, font_next); ! if (fl != NULL && fl->font_load != NULL && ! fl->font_name != NULL) { ! font = fl->font_load(fl->font_name); } ! if (font == NULL) ! font = &DEFAULT_FONT_DATA; ! ! *rows = (height - BORDER_PIXELS) / font->height; ! *cols = (width - BORDER_PIXELS) / font->width; } ! return (font); ! } ! /* Binary search for the glyph. Return 0 if not found. */ ! static uint16_t ! font_bisearch(const struct font_map *map, uint32_t len, uint32_t src) ! { ! int min, mid, max; ! min = 0; ! max = len - 1; + /* Empty font map. */ + if (len == 0) + return (0); + /* Character below minimal entry. */ + if (src < map[0].font_src) + return (0); + /* Optimization: ASCII characters occur very often. */ + if (src <= map[0].font_src + map[0].font_len) + return (src - map[0].font_src + map[0].font_dst); + /* Character above maximum entry. */ + if (src > map[max].font_src + map[max].font_len) + return (0); + + /* Binary search. */ + while (max >= min) { + mid = (min + max) / 2; + if (src < map[mid].font_src) + max = mid - 1; + else if (src > map[mid].font_src + map[mid].font_len) + min = mid + 1; + else + return (src - map[mid].font_src + map[mid].font_dst); + } + + return (0); } /* + * Return glyph bitmap. If glyph is not found, we will return bitmap + * for the first (offset 0) glyph. + */ + const uint8_t * + font_lookup(const struct font *vf, uint32_t c) + { + uint32_t src; + uint16_t dst; + size_t stride; + + src = TEM_CHAR(c); + + /* Substitute bold with normal if not found. */ + if (TEM_CHAR_ATTR(c) & TEM_ATTR_BOLD) { + dst = font_bisearch(vf->vf_map[VFNT_MAP_BOLD], + vf->vf_map_count[VFNT_MAP_BOLD], src); + if (dst != 0) + goto found; + } + dst = font_bisearch(vf->vf_map[VFNT_MAP_NORMAL], + vf->vf_map_count[VFNT_MAP_NORMAL], src); + + found: + stride = howmany(vf->vf_width, 8) * vf->vf_height; + return (&vf->vf_bytes[dst * stride]); + } + + /* * bit_to_pix4 is for 4-bit frame buffers. It will write one output byte * for each 2 bits of input bitmap. It inverts the input bits before * doing the output translation, for reverse video. * * Assuming foreground is 0001 and background is 0000...
*** 116,141 **** void font_bit_to_pix4( struct font *f, uint8_t *dest, ! uint8_t c, uint8_t fg_color, uint8_t bg_color) { int row; int byte; int i; ! uint8_t *cp; uint8_t data; uint8_t nibblett; int bytes_wide; ! cp = f->char_ptr[c]; ! bytes_wide = (f->width + 7) / 8; ! for (row = 0; row < f->height; row++) { for (byte = 0; byte < bytes_wide; byte++) { data = *cp++; for (i = 0; i < 4; i++) { nibblett = (data >> ((3-i) * 2)) & 0x3; switch (nibblett) { --- 240,265 ---- void font_bit_to_pix4( struct font *f, uint8_t *dest, ! uint32_t c, uint8_t fg_color, uint8_t bg_color) { int row; int byte; int i; ! const uint8_t *cp; uint8_t data; uint8_t nibblett; int bytes_wide; ! cp = font_lookup(f, c); ! bytes_wide = (f->vf_width + 7) / 8; ! for (row = 0; row < f->vf_height; row++) { for (byte = 0; byte < bytes_wide; byte++) { data = *cp++; for (i = 0; i < 4; i++) { nibblett = (data >> ((3-i) * 2)) & 0x3; switch (nibblett) {
*** 169,196 **** void font_bit_to_pix8( struct font *f, uint8_t *dest, ! uint8_t c, uint8_t fg_color, uint8_t bg_color) { int row; int byte; int i; ! uint8_t *cp; uint8_t data; int bytes_wide; uint8_t mask; int bitsleft, nbits; ! cp = f->char_ptr[c]; ! bytes_wide = (f->width + 7) / 8; ! for (row = 0; row < f->height; row++) { ! bitsleft = f->width; for (byte = 0; byte < bytes_wide; byte++) { data = *cp++; mask = 0x80; nbits = MIN(8, bitsleft); bitsleft -= nbits; --- 293,320 ---- void font_bit_to_pix8( struct font *f, uint8_t *dest, ! uint32_t c, uint8_t fg_color, uint8_t bg_color) { int row; int byte; int i; ! const uint8_t *cp; uint8_t data; int bytes_wide; uint8_t mask; int bitsleft, nbits; ! cp = font_lookup(f, c); ! bytes_wide = (f->vf_width + 7) / 8; ! for (row = 0; row < f->vf_height; row++) { ! bitsleft = f->vf_width; for (byte = 0; byte < bytes_wide; byte++) { data = *cp++; mask = 0x80; nbits = MIN(8, bitsleft); bitsleft -= nbits;
*** 201,212 **** } } } /* ! * bit_to_pix24 is for 24-bit frame buffers. It will write four output bytes * for each bit of input bitmap. It inverts the input bits before * doing the output translation, for reverse video. Note that each * 24-bit RGB value is finally stored in a 32-bit unsigned int, with the * high-order byte set to zero. * * Assuming foreground is 00000000 11111111 11111111 11111111 --- 325,446 ---- } } } /* ! * bit_to_pix16 is for 16-bit frame buffers. It will write two output bytes * for each bit of input bitmap. It inverts the input bits before + * doing the output translation, for reverse video. + * + * Assuming foreground is 11111111 11111111 + * and background is 00000000 00000000 + * An input data byte of 0x53 will output the bit pattern + * + * 00000000 00000000 + * 11111111 11111111 + * 00000000 00000000 + * 11111111 11111111 + * 00000000 00000000 + * 00000000 00000000 + * 11111111 11111111 + * 11111111 11111111 + * + */ + + void + font_bit_to_pix16( + struct font *f, + uint16_t *dest, + uint32_t c, + uint16_t fg_color16, + uint16_t bg_color16) + { + int row; + int byte; + int i; + const uint8_t *cp; + uint16_t data, d; + int bytes_wide; + int bitsleft, nbits; + + cp = font_lookup(f, c); + bytes_wide = (f->vf_width + 7) / 8; + + for (row = 0; row < f->vf_height; row++) { + bitsleft = f->vf_width; + for (byte = 0; byte < bytes_wide; byte++) { + data = *cp++; + nbits = MIN(8, bitsleft); + bitsleft -= nbits; + for (i = 0; i < nbits; i++) { + d = ((data << i) & 0x80 ? + fg_color16 : bg_color16); + *dest++ = d; + } + } + } + } + + /* + * bit_to_pix24 is for 24-bit frame buffers. It will write three output bytes + * for each bit of input bitmap. It inverts the input bits before + * doing the output translation, for reverse video. + * + * Assuming foreground is 11111111 11111111 11111111 + * and background is 00000000 00000000 00000000 + * An input data byte of 0x53 will output the bit pattern + * + * 00000000 00000000 00000000 + * 11111111 11111111 11111111 + * 00000000 00000000 00000000 + * 11111111 11111111 11111111 + * 00000000 00000000 00000000 + * 00000000 00000000 00000000 + * 11111111 11111111 11111111 + * 11111111 11111111 11111111 + * + */ + + void + font_bit_to_pix24( + struct font *f, + uint8_t *dest, + uint32_t c, + uint32_t fg_color32, + uint32_t bg_color32) + { + int row; + int byte; + int i; + const uint8_t *cp; + uint32_t data, d; + int bytes_wide; + int bitsleft, nbits; + + cp = font_lookup(f, c); + bytes_wide = (f->vf_width + 7) / 8; + + for (row = 0; row < f->vf_height; row++) { + bitsleft = f->vf_width; + for (byte = 0; byte < bytes_wide; byte++) { + data = *cp++; + nbits = MIN(8, bitsleft); + bitsleft -= nbits; + for (i = 0; i < nbits; i++) { + d = ((data << i) & 0x80 ? + fg_color32 : bg_color32); + *dest++ = d & 0xff; + *dest++ = (d >> 8) & 0xff; + *dest++ = (d >> 16) & 0xff; + } + } + } + } + + /* + * bit_to_pix32 is for 32-bit frame buffers. It will write four output bytes + * for each bit of input bitmap. It inverts the input bits before * doing the output translation, for reverse video. Note that each * 24-bit RGB value is finally stored in a 32-bit unsigned int, with the * high-order byte set to zero. * * Assuming foreground is 00000000 11111111 11111111 11111111
*** 223,254 **** * 00000000 11111111 11111111 11111111 * */ void ! font_bit_to_pix24( struct font *f, uint32_t *dest, ! uint8_t c, uint32_t fg_color32, uint32_t bg_color32) { int row; int byte; int i; ! uint8_t *cp; uint32_t data; int bytes_wide; int bitsleft, nbits; ! cp = f->char_ptr[c]; ! bytes_wide = (f->width + 7) / 8; ! for (row = 0; row < f->height; row++) { ! bitsleft = f->width; for (byte = 0; byte < bytes_wide; byte++) { data = *cp++; nbits = MIN(8, bitsleft); bitsleft -= nbits; for (i = 0; i < nbits; i++) { *dest++ = ((data << i) & 0x80 ? fg_color32 : bg_color32); --- 457,496 ---- * 00000000 11111111 11111111 11111111 * */ void ! font_bit_to_pix32( struct font *f, uint32_t *dest, ! uint32_t c, uint32_t fg_color32, uint32_t bg_color32) { int row; int byte; int i; ! const uint8_t *cp, *ul; uint32_t data; int bytes_wide; int bitsleft, nbits; ! if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE) ! ul = font_lookup(f, 0x0332); /* combining low line */ ! else ! ul = NULL; ! cp = font_lookup(f, c); ! bytes_wide = (f->vf_width + 7) / 8; ! ! for (row = 0; row < f->vf_height; row++) { ! bitsleft = f->vf_width; for (byte = 0; byte < bytes_wide; byte++) { + if (ul == NULL) data = *cp++; + else + data = *cp++ | *ul++; nbits = MIN(8, bitsleft); bitsleft -= nbits; for (i = 0; i < nbits; i++) { *dest++ = ((data << i) & 0x80 ? fg_color32 : bg_color32);