Modify Linux Kernel Font

Author Artem Butusov · Published on January 10th, 2016

Reasons

There are not so much reasons to change integrated in kernel fonts.

But I will publish my reasons for that:

Intro

If I can’t change console resolution then I could change font size! The idea is simple, if default kernel font 8x16 looks fine on 1280x800 then 16x32 will look fine on 2560x1600. We need to find good monospace bitmap font with unicode and ascii support. I suggest to use Terminus. I will show here how to set Terminus font as kernel console font based on Gentoo Linux distribution.

The procedure below will double font in size for any system with framebuffer, so it’s suitable for MacBookPro Retina 15" and others.

Install terminus font

emerge terminus-font

Install PSF tools

echo media-gfx/psftools >> /etc/portage/package.accept_keywords/psftools
emerge media-gfx/psftools -1

Convert PSF font to kernel font

To simplify kernel configuration we will just overwrite integrated font_8x16.c font in kernel with terminus 16x32 bold ascii.

mkdir ~/new-font
cd ~/new-font
cp /usr/share/consolefonts/ter-i32b.psf.gz .
gunzip ter-i32b.psf.gz

Here:

The we need to dump font:

psf2inc ter-i32b.psf > ter-i32b.inc

The we need to extract just font bitmap data from dump:

cat ter-i32b.inc | sed '0,/Char height/d' | sed '2049,$d' > ter-i32b.hex

2049 = 1 + (FontCharsNumber * FontWidth * FontHeight / DotsPerByte) / BytesPerLine = 1 + (256 * 16 * 32 / 8) / 8

But sometimes it could be easier to just open inc file and remove useless header and everything after last 256 glyph which has comment /* 255 */

We will use hex code as default text for font file:

cat ter-i32b.hex > font_8x16.c

Then we need edit font file so he will look like below:

#include <linux/font.h>
#include <linux/module.h>
#define FONTDATAMAX 16384
static const unsigned char fontdata_8x16[FONTDATAMAX] = {
        {GLYPH HEX SHOULD BE HERE}
};
const struct font_desc font_vga_8x16 = {
        .idx    = VGA8x16_IDX,
        .name   = "VGA8x16",
        .width  = 16,
        .height = 32,
        .data   = fontdata_8x16,
        .pref   = 0,
};
EXPORT_SYMBOL(font_vga_8x16);

We need to fill fontdata_8x16 with data from ter-i32b.hex. We need to change FONTDATAMAX to make sure that FONTDATAMAX = FontCharsNumber * FontWidth * FontHeight / DotsPerByte Also we need to change font_vga_8x16.width and font_vga_8x16.height. All remaining text is grabbed from original font_8x16.c

Install kernel font

mv /usr/src/linux/lib/fonts/font_8x16.c /usr/src/linux/lib/fonts/font_8x16.c.org
cp font_8x16.c /usr/src/linux/lib/fonts/
cd ~
rm ~/new-font -rf
rm /usr/src/linux/lib/fonts/*.o
genkernel kernel --no-clean

Here:

Set console font

OpenRC

After kernel will boot we could switch console to Terminus Unicode font.

/etc/conf.d/consolefont:

consolefont="ter-v32b"

Set console font:

/etc/init.d/consolefont restart

Set console font on boot:

rc-update add consolefont default

systemd

setfont ter-v32b
nano /etc/vconsole.conf
FONT=ter-v32b

Done

Reboot and you will be able to see new font in kernel boot console and the same font in system boot console. And font will be readable on MacBookPro Retina 13".