diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-04-15 08:37:45 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-04-15 08:37:45 -0700 |
| commit | afac4c66d1aa6396ce44d94fe895d7b61e085fd4 (patch) | |
| tree | 57a5e3b6b5c9aa63ba746a366224e3b605c804ca /lib | |
| parent | 00c6649bafef628955569dd39a59e3170e48f7b5 (diff) | |
| parent | a31e4518bec70333a0a98f2946a12b53b45fe5b9 (diff) | |
Merge tag 'fbdev-for-7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/linux-fbdev
Pull fbdev updates from Helge Deller:
"A major refactorization by Thomas Zimmermann from SUSE regarding
handling of console font data, addition of helpers for console font
rotation and split into individual components for glyphs, fonts and
the overall fbcon state.
And there is the round of usual code cleanups and fixes:
Cleanups:
- atyfb: Remove unused fb_list (Geert Uytterhoeven)
- goldfishfb, wmt_ge_rops: use devm_platform_ioremap_resource() (Amin GATTOUT)
- matroxfb: Mark variable with __maybe_unused (Andy Shevchenko)
- omapfb: Add missing error check for clk_get() (Chen Ni)
- tdfxfb: Make the VGA register initialisation a bit more obvious (Daniel Palmer)
- macfb: Replace deprecated strcpy with strscpy (Thorsten Blum)
Fixes:
- tdfxfb, udlfb: avoid divide-by-zero on FBIOPUT_VSCREENINFO (Greg Kroah-Hartman)
- omap2: fix inconsistent lock returns in omapfb_mmap (Hongling Zeng)
- viafb: check ioremap return value in viafb_lcd_get_mobile_state (Wang Jun)"
* tag 'fbdev-for-7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/linux-fbdev: (40 commits)
fbdev: udlfb: avoid divide-by-zero on FBIOPUT_VSCREENINFO
fbdev: tdfxfb: avoid divide-by-zero on FBIOPUT_VSCREENINFO
fbdev: omap2: fix inconsistent lock returns in omapfb_mmap
MAINTAINERS: Add dedicated entry for fbcon
fbcon: Put font-rotation state into separate struct
fbcon: Fill cursor mask in helper function
lib/fonts: Implement font rotation
lib/fonts: Refactor glyph-rotation helpers
lib/fonts: Refactor glyph-pattern helpers
lib/fonts: Implement glyph rotation
lib/fonts: Clean up Makefile
lib/fonts: Provide helpers for calculating glyph pitch and size
vt: Implement helpers for struct vc_font in source file
fbcon: Avoid OOB font access if console rotation fails
fbdev: atyfb: Remove unused fb_list
fbdev: matroxfb: Mark variable with __maybe_unused to avoid W=1 build break
fbdev: update help text for CONFIG_FB_NVIDIA
fbdev: omapfb: Add missing error check for clk_get()
fbdev: viafb: check ioremap return value in viafb_lcd_get_mobile_state
lib/fonts: Remove internal symbols and macros from public header file
...
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/fonts/Makefile | 36 | ||||
| -rw-r--r-- | lib/fonts/font.h | 38 | ||||
| -rw-r--r-- | lib/fonts/font_10x18.c | 2 | ||||
| -rw-r--r-- | lib/fonts/font_6x10.c | 3 | ||||
| -rw-r--r-- | lib/fonts/font_6x11.c | 2 | ||||
| -rw-r--r-- | lib/fonts/font_6x8.c | 3 | ||||
| -rw-r--r-- | lib/fonts/font_7x14.c | 2 | ||||
| -rw-r--r-- | lib/fonts/font_8x16.c | 3 | ||||
| -rw-r--r-- | lib/fonts/font_8x8.c | 2 | ||||
| -rw-r--r-- | lib/fonts/font_acorn_8x8.c | 4 | ||||
| -rw-r--r-- | lib/fonts/font_mini_4x6.c | 10 | ||||
| -rw-r--r-- | lib/fonts/font_pearl_8x8.c | 2 | ||||
| -rw-r--r-- | lib/fonts/font_rotate.c | 275 | ||||
| -rw-r--r-- | lib/fonts/font_sun12x22.c | 3 | ||||
| -rw-r--r-- | lib/fonts/font_sun8x16.c | 3 | ||||
| -rw-r--r-- | lib/fonts/font_ter10x18.c | 4 | ||||
| -rw-r--r-- | lib/fonts/font_ter16x32.c | 4 | ||||
| -rw-r--r-- | lib/fonts/fonts.c | 232 |
18 files changed, 589 insertions, 39 deletions
diff --git a/lib/fonts/Makefile b/lib/fonts/Makefile index 30a85a4292fa..7202a70a56ef 100644 --- a/lib/fonts/Makefile +++ b/lib/fonts/Makefile @@ -1,23 +1,23 @@ # SPDX-License-Identifier: GPL-2.0 # Font handling -font-objs := fonts.o +font-y := fonts.o +font-$(CONFIG_FRAMEBUFFER_CONSOLE_ROTATION) += font_rotate.o -font-objs-$(CONFIG_FONT_SUN8x16) += font_sun8x16.o -font-objs-$(CONFIG_FONT_SUN12x22) += font_sun12x22.o -font-objs-$(CONFIG_FONT_8x8) += font_8x8.o -font-objs-$(CONFIG_FONT_8x16) += font_8x16.o -font-objs-$(CONFIG_FONT_6x11) += font_6x11.o -font-objs-$(CONFIG_FONT_7x14) += font_7x14.o -font-objs-$(CONFIG_FONT_10x18) += font_10x18.o -font-objs-$(CONFIG_FONT_PEARL_8x8) += font_pearl_8x8.o -font-objs-$(CONFIG_FONT_ACORN_8x8) += font_acorn_8x8.o -font-objs-$(CONFIG_FONT_MINI_4x6) += font_mini_4x6.o -font-objs-$(CONFIG_FONT_6x10) += font_6x10.o -font-objs-$(CONFIG_FONT_TER10x18) += font_ter10x18.o -font-objs-$(CONFIG_FONT_TER16x32) += font_ter16x32.o -font-objs-$(CONFIG_FONT_6x8) += font_6x8.o +# Built-in fonts; sorted by Family-Size in ascending order +font-$(CONFIG_FONT_6x8) += font_6x8.o +font-$(CONFIG_FONT_6x10) += font_6x10.o +font-$(CONFIG_FONT_6x11) += font_6x11.o +font-$(CONFIG_FONT_7x14) += font_7x14.o +font-$(CONFIG_FONT_8x8) += font_8x8.o +font-$(CONFIG_FONT_8x16) += font_8x16.o +font-$(CONFIG_FONT_10x18) += font_10x18.o +font-$(CONFIG_FONT_ACORN_8x8) += font_acorn_8x8.o +font-$(CONFIG_FONT_MINI_4x6) += font_mini_4x6.o +font-$(CONFIG_FONT_PEARL_8x8) += font_pearl_8x8.o +font-$(CONFIG_FONT_SUN8x16) += font_sun8x16.o +font-$(CONFIG_FONT_SUN12x22) += font_sun12x22.o +font-$(CONFIG_FONT_TER10x18) += font_ter10x18.o +font-$(CONFIG_FONT_TER16x32) += font_ter16x32.o -font-objs += $(font-objs-y) - -obj-$(CONFIG_FONT_SUPPORT) += font.o +obj-$(CONFIG_FONT_SUPPORT) += font.o diff --git a/lib/fonts/font.h b/lib/fonts/font.h new file mode 100644 index 000000000000..4f1adf0b6b54 --- /dev/null +++ b/lib/fonts/font.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _LIB_FONTS_FONT_H +#define _LIB_FONTS_FONT_H + +#include <linux/font.h> + +/* + * Font data + */ + +#define FONT_EXTRA_WORDS 4 + +struct font_data { + unsigned int extra[FONT_EXTRA_WORDS]; + unsigned char data[]; +} __packed; + +/* + * Built-in fonts + */ + +#define VGA8x8_IDX 0 +#define VGA8x16_IDX 1 +#define PEARL8x8_IDX 2 +#define VGA6x11_IDX 3 +#define FONT7x14_IDX 4 +#define FONT10x18_IDX 5 +#define SUN8x16_IDX 6 +#define SUN12x22_IDX 7 +#define ACORN8x8_IDX 8 +#define MINI4x6_IDX 9 +#define FONT6x10_IDX 10 +#define TER16x32_IDX 11 +#define FONT6x8_IDX 12 +#define TER10x18_IDX 13 + +#endif diff --git a/lib/fonts/font_10x18.c b/lib/fonts/font_10x18.c index 5d940db626e7..10edebc4bb74 100644 --- a/lib/fonts/font_10x18.c +++ b/lib/fonts/font_10x18.c @@ -4,7 +4,7 @@ * by Jurriaan Kalkman 06-2005 * ********************************/ -#include <linux/font.h> +#include "font.h" #define FONTDATAMAX 9216 diff --git a/lib/fonts/font_6x10.c b/lib/fonts/font_6x10.c index e65df019e0d2..660d3a371b30 100644 --- a/lib/fonts/font_6x10.c +++ b/lib/fonts/font_6x10.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 -#include <linux/font.h> + +#include "font.h" #define FONTDATAMAX 2560 diff --git a/lib/fonts/font_6x11.c b/lib/fonts/font_6x11.c index bd76b3f6b635..671487ccc172 100644 --- a/lib/fonts/font_6x11.c +++ b/lib/fonts/font_6x11.c @@ -5,7 +5,7 @@ /* */ /**********************************************/ -#include <linux/font.h> +#include "font.h" #define FONTDATAMAX (11*256) diff --git a/lib/fonts/font_6x8.c b/lib/fonts/font_6x8.c index 06ace7792521..5811ee07f4d8 100644 --- a/lib/fonts/font_6x8.c +++ b/lib/fonts/font_6x8.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 -#include <linux/font.h> + +#include "font.h" #define FONTDATAMAX 2048 diff --git a/lib/fonts/font_7x14.c b/lib/fonts/font_7x14.c index a2f561c9fa04..0c7475d643c8 100644 --- a/lib/fonts/font_7x14.c +++ b/lib/fonts/font_7x14.c @@ -4,7 +4,7 @@ /* by Jurriaan Kalkman 05-2005 */ /**************************************/ -#include <linux/font.h> +#include "font.h" #define FONTDATAMAX 3584 diff --git a/lib/fonts/font_8x16.c b/lib/fonts/font_8x16.c index 06ae14088514..523e95c75569 100644 --- a/lib/fonts/font_8x16.c +++ b/lib/fonts/font_8x16.c @@ -5,9 +5,10 @@ /* */ /**********************************************/ -#include <linux/font.h> #include <linux/module.h> +#include "font.h" + #define FONTDATAMAX 4096 static const struct font_data fontdata_8x16 = { diff --git a/lib/fonts/font_8x8.c b/lib/fonts/font_8x8.c index 69570b8c31af..e5b697fc9675 100644 --- a/lib/fonts/font_8x8.c +++ b/lib/fonts/font_8x8.c @@ -5,7 +5,7 @@ /* */ /**********************************************/ -#include <linux/font.h> +#include "font.h" #define FONTDATAMAX 2048 diff --git a/lib/fonts/font_acorn_8x8.c b/lib/fonts/font_acorn_8x8.c index 18755c33d249..36c51016769d 100644 --- a/lib/fonts/font_acorn_8x8.c +++ b/lib/fonts/font_acorn_8x8.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* Acorn-like font definition, with PC graphics characters */ -#include <linux/font.h> +#include "font.h" #define FONTDATAMAX 2048 @@ -68,7 +68,7 @@ static const struct font_data acorndata_8x8 = { /* 3A */ 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, /* : */ /* 3B */ 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x30, /* ; */ /* 3C */ 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00, /* < */ -/* 3D */ 0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00, /* = */ +/* 3D */ 0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00, /* = */ /* 3E */ 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x00, /* > */ /* 3F */ 0x3C, 0x66, 0x0C, 0x18, 0x18, 0x00, 0x18, 0x00, /* ? */ /* 40 */ 0x3C, 0x66, 0x6E, 0x6A, 0x6E, 0x60, 0x3C, 0x00, /* @ */ diff --git a/lib/fonts/font_mini_4x6.c b/lib/fonts/font_mini_4x6.c index 8d39fd447952..dc919c160dde 100644 --- a/lib/fonts/font_mini_4x6.c +++ b/lib/fonts/font_mini_4x6.c @@ -18,15 +18,15 @@ s{((0x)?[0-9a-fA-F]+)(.*\[([\*\ ]{4})\])}{ ($num,$pat,$bits) = ($1,$3,$4); - + $bits =~ s/([^\s0])|(.)/ defined($1) + 0 /ge; - + $num = ord(pack("B8", $bits)); $num |= $num >> 4; $num = sprintf("0x%.2x", $num); - + #print "$num,$pat,$bits\n"; - + $num . $pat; }ge; @@ -39,7 +39,7 @@ __END__; MSBit to LSBit = left to right. */ -#include <linux/font.h> +#include "font.h" #define FONTDATAMAX 1536 diff --git a/lib/fonts/font_pearl_8x8.c b/lib/fonts/font_pearl_8x8.c index ae98ca17982e..2438b374acea 100644 --- a/lib/fonts/font_pearl_8x8.c +++ b/lib/fonts/font_pearl_8x8.c @@ -10,7 +10,7 @@ /* */ /**********************************************/ -#include <linux/font.h> +#include "font.h" #define FONTDATAMAX 2048 diff --git a/lib/fonts/font_rotate.c b/lib/fonts/font_rotate.c new file mode 100644 index 000000000000..065e0fc0667b --- /dev/null +++ b/lib/fonts/font_rotate.c @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Font rotation + * + * Copyright (C) 2005 Antonino Daplas <adaplas @pol.net> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include <linux/errno.h> +#include <linux/export.h> +#include <linux/math.h> +#include <linux/overflow.h> +#include <linux/slab.h> +#include <linux/string.h> + +#include "font.h" + +/* number of bits per line */ +static unsigned int font_glyph_bit_pitch(unsigned int width) +{ + return round_up(width, 8); +} + +static unsigned int __font_glyph_pos(unsigned int x, unsigned int y, unsigned int bit_pitch, + unsigned int *bit) +{ + unsigned int off = y * bit_pitch + x; + unsigned int bit_shift = off % 8; + + *bit = 0x80 >> bit_shift; /* MSB has position 0, LSB has position 7 */ + + return off / 8; +} + +static bool font_glyph_test_bit(const unsigned char *glyph, unsigned int x, unsigned int y, + unsigned int bit_pitch) +{ + unsigned int bit; + unsigned int i = __font_glyph_pos(x, y, bit_pitch, &bit); + + return glyph[i] & bit; +} + +static void font_glyph_set_bit(unsigned char *glyph, unsigned int x, unsigned int y, + unsigned int bit_pitch) +{ + unsigned int bit; + unsigned int i = __font_glyph_pos(x, y, bit_pitch, &bit); + + glyph[i] |= bit; +} + +static void __font_glyph_rotate_90(const unsigned char *glyph, + unsigned int width, unsigned int height, + unsigned char *out) +{ + unsigned int x, y; + unsigned int shift = (8 - (height % 8)) & 7; + unsigned int bit_pitch = font_glyph_bit_pitch(width); + unsigned int out_bit_pitch = font_glyph_bit_pitch(height); + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + if (font_glyph_test_bit(glyph, x, y, bit_pitch)) { + font_glyph_set_bit(out, out_bit_pitch - 1 - y - shift, x, + out_bit_pitch); + } + } + } +} + +/** + * font_glyph_rotate_90 - Rotate a glyph pattern by 90° in clockwise direction + * @glyph: The glyph to rotate + * @width: The glyph width in bits per scanline + * @height: The number of scanlines in the glyph + * @out: The rotated glyph bitmap + * + * The parameters @width and @height refer to the input glyph given in @glyph. + * The caller has to provide the output buffer @out of sufficient size to hold + * the rotated glyph. Rotating by 90° flips the width and height for the output + * glyph. Depending on the glyph pitch, the size of the output glyph can be + * different than the size of the input. Callers have to take this into account + * when allocating the output memory. + */ +void font_glyph_rotate_90(const unsigned char *glyph, unsigned int width, unsigned int height, + unsigned char *out) +{ + memset(out, 0, font_glyph_size(height, width)); /* flip width/height */ + + __font_glyph_rotate_90(glyph, width, height, out); +} +EXPORT_SYMBOL_GPL(font_glyph_rotate_90); + +static void __font_glyph_rotate_180(const unsigned char *glyph, + unsigned int width, unsigned int height, + unsigned char *out) +{ + unsigned int x, y; + unsigned int shift = (8 - (width % 8)) & 7; + unsigned int bit_pitch = font_glyph_bit_pitch(width); + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + if (font_glyph_test_bit(glyph, x, y, bit_pitch)) { + font_glyph_set_bit(out, width - (1 + x + shift), height - (1 + y), + bit_pitch); + } + } + } +} + +/** + * font_glyph_rotate_180 - Rotate a glyph pattern by 180° + * @glyph: The glyph to rotate + * @width: The glyph width in bits per scanline + * @height: The number of scanlines in the glyph + * @out: The rotated glyph bitmap + * + * The parameters @width and @height refer to the input glyph given in @glyph. + * The caller has to provide the output buffer @out of sufficient size to hold + * the rotated glyph. + */ +void font_glyph_rotate_180(const unsigned char *glyph, unsigned int width, unsigned int height, + unsigned char *out) +{ + memset(out, 0, font_glyph_size(width, height)); + + __font_glyph_rotate_180(glyph, width, height, out); +} +EXPORT_SYMBOL_GPL(font_glyph_rotate_180); + +static void __font_glyph_rotate_270(const unsigned char *glyph, + unsigned int width, unsigned int height, + unsigned char *out) +{ + unsigned int x, y; + unsigned int shift = (8 - (width % 8)) & 7; + unsigned int bit_pitch = font_glyph_bit_pitch(width); + unsigned int out_bit_pitch = font_glyph_bit_pitch(height); + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + if (font_glyph_test_bit(glyph, x, y, bit_pitch)) + font_glyph_set_bit(out, y, bit_pitch - 1 - x - shift, + out_bit_pitch); + } + } +} + +/** + * font_glyph_rotate_270 - Rotate a glyph pattern by 270° in clockwise direction + * @glyph: The glyph to rotate + * @width: The glyph width in bits per scanline + * @height: The number of scanlines in the glyph + * @out: The rotated glyph bitmap + * + * The parameters @width and @height refer to the input glyph given in @glyph. + * The caller has to provide the output buffer @out of sufficient size to hold + * the rotated glyph. Rotating by 270° flips the width and height for the output + * glyph. Depending on the glyph pitch, the size of the output glyph can be + * different than the size of the input. Callers have to take this into account + * when allocating the output memory. + */ +void font_glyph_rotate_270(const unsigned char *glyph, unsigned int width, unsigned int height, + unsigned char *out) +{ + memset(out, 0, font_glyph_size(height, width)); /* flip width/height */ + + __font_glyph_rotate_270(glyph, width, height, out); +} +EXPORT_SYMBOL_GPL(font_glyph_rotate_270); + +/** + * font_data_rotate - Rotate font data by multiples of 90° + * @fd: The font data to rotate + * @width: The glyph width in bits per scanline + * @height: The number of scanlines in the glyph + * @charcount: The number of glyphs in the font + * @steps: Number of rotation steps of 90° + * @buf: Preallocated output buffer; can be NULL + * @bufsize: The size of @buf in bytes; can be NULL + * + * The parameters @width and @height refer to the visible number of pixels + * and scanlines in a single glyph. The number of glyphs is given in @charcount. + * Rotation happens in steps of 90°. The @steps parameter can have any value, + * but only 0 to 3 produce distinct results. With 4 or higher, a full rotation + * has been performed. You can pass any value for @steps and the helper will + * perform the appropriate rotation. Note that the returned buffer is not + * compatible with font_data_t. It only contains glyph data in the same format + * as returned by font_data_buf(). Callers are responsible to free the returned + * buffer with kfree(). Font rotation typically happens when displays get + * re-oriented. To avoid unnecessary re-allocation of the memory buffer, the + * caller can pass in an earlier result buffer in @buf for reuse. The old and + * new buffer sizes are given and retrieved by the caller in @bufsize. The + * allocation semantics are compatible with krealloc(). + * + * Returns: + * A buffer with rotated glyphs on success, or an error pointer otherwise + */ +unsigned char *font_data_rotate(font_data_t *fd, unsigned int width, unsigned int height, + unsigned int charcount, unsigned int steps, + unsigned char *buf, size_t *bufsize) +{ + const unsigned char *src = font_data_buf(fd); + unsigned int s_cellsize = font_glyph_size(width, height); + unsigned int d_cellsize, i; + unsigned char *dst; + size_t size; + + steps %= 4; + + switch (steps) { + case 0: + case 2: + d_cellsize = s_cellsize; + break; + case 1: + case 3: + d_cellsize = font_glyph_size(height, width); /* flip width/height */ + break; + } + + if (check_mul_overflow(charcount, d_cellsize, &size)) + return ERR_PTR(-EINVAL); + + if (!buf || !bufsize || size > *bufsize) { + dst = kmalloc_array(charcount, d_cellsize, GFP_KERNEL); + if (!dst) + return ERR_PTR(-ENOMEM); + + kfree(buf); + buf = dst; + if (bufsize) + *bufsize = size; + } else { + dst = buf; + } + + switch (steps) { + case 0: + memcpy(dst, src, size); + break; + case 1: + memset(dst, 0, size); + for (i = 0; i < charcount; ++i) { + __font_glyph_rotate_90(src, width, height, dst); + src += s_cellsize; + dst += d_cellsize; + } + break; + case 2: + memset(dst, 0, size); + for (i = 0; i < charcount; ++i) { + __font_glyph_rotate_180(src, width, height, dst); + src += s_cellsize; + dst += d_cellsize; + } + break; + case 3: + memset(dst, 0, size); + for (i = 0; i < charcount; ++i) { + __font_glyph_rotate_270(src, width, height, dst); + src += s_cellsize; + dst += d_cellsize; + } + break; + } + + return buf; +} +EXPORT_SYMBOL_GPL(font_data_rotate); diff --git a/lib/fonts/font_sun12x22.c b/lib/fonts/font_sun12x22.c index 91daf5ab8b6b..2afbc144bea8 100644 --- a/lib/fonts/font_sun12x22.c +++ b/lib/fonts/font_sun12x22.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 -#include <linux/font.h> + +#include "font.h" #define FONTDATAMAX 11264 diff --git a/lib/fonts/font_sun8x16.c b/lib/fonts/font_sun8x16.c index 81bb4eeae04e..2b7b2d8e548a 100644 --- a/lib/fonts/font_sun8x16.c +++ b/lib/fonts/font_sun8x16.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 -#include <linux/font.h> + +#include "font.h" #define FONTDATAMAX 4096 diff --git a/lib/fonts/font_ter10x18.c b/lib/fonts/font_ter10x18.c index 80356e9d56c7..3f30b4a211ab 100644 --- a/lib/fonts/font_ter10x18.c +++ b/lib/fonts/font_ter10x18.c @@ -1,7 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 -#include <linux/font.h> + #include <linux/module.h> +#include "font.h" + #define FONTDATAMAX 9216 static const struct font_data fontdata_ter10x18 = { diff --git a/lib/fonts/font_ter16x32.c b/lib/fonts/font_ter16x32.c index 5baedc573dd6..93616cffe642 100644 --- a/lib/fonts/font_ter16x32.c +++ b/lib/fonts/font_ter16x32.c @@ -1,7 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 -#include <linux/font.h> + #include <linux/module.h> +#include "font.h" + #define FONTDATAMAX 16384 static const struct font_data fontdata_ter16x32 = { diff --git a/lib/fonts/fonts.c b/lib/fonts/fonts.c index a7f118b30171..f5d5333450a0 100644 --- a/lib/fonts/fonts.c +++ b/lib/fonts/fonts.c @@ -12,13 +12,241 @@ * for more details. */ +#include <linux/container_of.h> +#include <linux/kd.h> #include <linux/module.h> -#include <linux/types.h> +#include <linux/overflow.h> +#include <linux/slab.h> #include <linux/string.h> +#include <linux/types.h> + #if defined(__mc68000__) #include <asm/setup.h> #endif -#include <linux/font.h> + +#include "font.h" + +#define console_font_pitch(font) font_glyph_pitch((font)->width) + +/* + * Helpers for font_data_t + */ + +/* Extra word getters */ +#define REFCOUNT(fd) (((int *)(fd))[-1]) +#define FNTSIZE(fd) (((int *)(fd))[-2]) +#define FNTSUM(fd) (((int *)(fd))[-4]) + +static struct font_data *to_font_data_struct(font_data_t *fd) +{ + return container_of(fd, struct font_data, data[0]); +} + +static bool font_data_is_internal(font_data_t *fd) +{ + return !REFCOUNT(fd); /* internal fonts have no reference counting */ +} + +static void font_data_free(font_data_t *fd) +{ + kfree(to_font_data_struct(fd)); +} + +/** + * font_data_import - Allocates and initializes font data from user space + * @font: A font from user space + * @vpitch: The size of a single glyph in @font in bytes + * @calc_csum: An optional helper to calculate a chechsum + * + * Font data from user space must be translated to the kernel's format. The + * font's glyph geometry and data is provided in @font. The parameter @vpitch + * gives the number of bytes per glyph, including trailing bytes. + * + * The parameter @calc_csum is optional. Fbcon passes crc32() to calculate the + * font data's checksum. + * + * Returns: + * Newly initialized font data on success, or a pointer-encoded errno value otherwise. + */ +font_data_t *font_data_import(const struct console_font *font, unsigned int vpitch, + u32 (*calc_csum)(u32, const void *, size_t)) +{ + unsigned int pitch = console_font_pitch(font); + unsigned int h = font->height; + unsigned int charcount = font->charcount; + const unsigned char *data = font->data; + u32 csum = 0; + struct font_data *font_data; + int size, alloc_size; + unsigned int i; + font_data_t *fd; + + /* Check for integer overflow in font-size calculation */ + if (check_mul_overflow(h, pitch, &size) || + check_mul_overflow(size, charcount, &size)) + return ERR_PTR(-EINVAL); + + /* Check for overflow in allocation size calculation */ + if (check_add_overflow(sizeof(*font_data), size, &alloc_size)) + return ERR_PTR(-EINVAL); + + font_data = kmalloc(alloc_size, GFP_USER); + if (!font_data) + return ERR_PTR(-ENOMEM); + memset(font_data->extra, 0, sizeof(font_data->extra)); + + for (i = 0; i < charcount; ++i) + memcpy(font_data->data + i * h * pitch, data + i * vpitch * pitch, h * pitch); + + if (calc_csum) + csum = calc_csum(0, font_data->data, size); + + fd = font_data->data; + REFCOUNT(fd) = 1; /* start with reference acquired */ + FNTSIZE(fd) = size; + FNTSUM(fd) = csum; + + return fd; +} +EXPORT_SYMBOL_GPL(font_data_import); + +/** + * font_data_get - Acquires a reference on font data + * @fd: Font data + * + * Font data from user space is reference counted. The helper + * font_data_get() increases the reference counter by one. Invoke + * font_data_put() to release the reference. + * + * Internal font data is located in read-only memory. In this case + * the helper returns success without modifying the counter field. + * It is still required to call font_data_put() on internal font data. + */ +void font_data_get(font_data_t *fd) +{ + if (font_data_is_internal(fd)) + return; /* never ref static data */ + + if (WARN_ON(!REFCOUNT(fd))) + return; /* should never be 0 */ + ++REFCOUNT(fd); +} +EXPORT_SYMBOL_GPL(font_data_get); + +/** + * font_data_put - Release a reference on font data + * @fd: Font data + * + * Font data from user space is reference counted. The helper + * font_data_put() decreases the reference counter by one. If this was + * the final reference, it frees the allocated memory. + * + * Internal font data is located in read-only memory. In this case + * the helper returns success without modifying the counter field. + * + * Returns: + * True if the font data's memory buffer has been freed, false otherwise. + */ +bool font_data_put(font_data_t *fd) +{ + unsigned int count; + + if (font_data_is_internal(fd)) + return false; /* never unref static data */ + + if (WARN_ON(!REFCOUNT(fd))) + return false; /* should never be 0 */ + + count = --REFCOUNT(fd); + if (!count) + font_data_free(fd); + + return !count; +} +EXPORT_SYMBOL_GPL(font_data_put); + +/** + * font_data_size - Return size of the font data in bytes + * @fd: Font data + * + * Returns: + * The number of bytes in the given font data. + */ +unsigned int font_data_size(font_data_t *fd) +{ + return FNTSIZE(fd); +} +EXPORT_SYMBOL_GPL(font_data_size); + +/** + * font_data_is_equal - Compares font data for equality + * @lhs: Left-hand side font data + * @rhs: Right-hand-size font data + * + * Font data is equal if is constain the same sequence of values. The + * helper also use the checksum, if both arguments contain it. Font data + * coming from different origins, internal or from user space, is never + * equal. Allowing this would break reference counting. + * + * Returns: + * True if the given font data is equal, false otherwise. + */ +bool font_data_is_equal(font_data_t *lhs, font_data_t *rhs) +{ + if (font_data_is_internal(lhs) != font_data_is_internal(rhs)) + return false; + if (font_data_size(lhs) != font_data_size(rhs)) + return false; + if (FNTSUM(lhs) && FNTSUM(rhs) && FNTSUM(lhs) != FNTSUM(rhs)) + return false; + + return !memcmp(lhs, rhs, FNTSIZE(lhs)); +} +EXPORT_SYMBOL_GPL(font_data_is_equal); + +/** + * font_data_export - Stores font data for user space + * @fd: Font data + * @font: A font for user space + * @vpitch: The size of a single glyph in @font in bytes + * + * Store the font data given in @fd to the font in @font. Values and + * pointers in @font are pre-initialized. This helper mostly checks some + * corner cases and translates glyph sizes according to the value given + * @vpitch. + * + * Returns: + * 0 on success, or a negative errno code otherwise. + */ +int font_data_export(font_data_t *fd, struct console_font *font, unsigned int vpitch) +{ + const unsigned char *font_data = font_data_buf(fd); + unsigned char *data = font->data; + unsigned int pitch = console_font_pitch(font); + unsigned int glyphsize, i; + + if (!font->width || !font->height || !font->charcount || !font->data) + return 0; + + glyphsize = font->height * pitch; + + if (font->charcount * glyphsize > font_data_size(fd)) + return -EINVAL; + + for (i = 0; i < font->charcount; i++) { + memcpy(data, font_data, glyphsize); + memset(data + glyphsize, 0, pitch * vpitch - glyphsize); + data += pitch * vpitch; + font_data += glyphsize; + } + + return 0; +} +EXPORT_SYMBOL_GPL(font_data_export); + +/* + * Font lookup + */ static const struct font_desc *fonts[] = { #ifdef CONFIG_FONT_8x8 |
