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);