summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/fonts/fonts.c62
1 files changed, 62 insertions, 0 deletions
diff --git a/lib/fonts/fonts.c b/lib/fonts/fonts.c
index 3fb76d185647..16e75c3d2a0f 100644
--- a/lib/fonts/fonts.c
+++ b/lib/fonts/fonts.c
@@ -14,7 +14,9 @@
#include <linux/container_of.h>
#include <linux/font.h>
+#include <linux/kd.h>
#include <linux/module.h>
+#include <linux/overflow.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/types.h>
@@ -23,6 +25,8 @@
#include <asm/setup.h>
#endif
+#define console_font_pitch(font) DIV_ROUND_UP((font)->width, 8)
+
/*
* Helpers for font_data_t
*/
@@ -43,6 +47,64 @@ static void font_data_free(font_data_t *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
*