127cf7d04SAleksandr Rybalko /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni *
427cf7d04SAleksandr Rybalko * Copyright (c) 2009 The FreeBSD Foundation
527cf7d04SAleksandr Rybalko *
627cf7d04SAleksandr Rybalko * This software was developed by Ed Schouten under sponsorship from the
727cf7d04SAleksandr Rybalko * FreeBSD Foundation.
827cf7d04SAleksandr Rybalko *
927cf7d04SAleksandr Rybalko * Redistribution and use in source and binary forms, with or without
1027cf7d04SAleksandr Rybalko * modification, are permitted provided that the following conditions
1127cf7d04SAleksandr Rybalko * are met:
1227cf7d04SAleksandr Rybalko * 1. Redistributions of source code must retain the above copyright
1327cf7d04SAleksandr Rybalko * notice, this list of conditions and the following disclaimer.
1427cf7d04SAleksandr Rybalko * 2. Redistributions in binary form must reproduce the above copyright
1527cf7d04SAleksandr Rybalko * notice, this list of conditions and the following disclaimer in the
1627cf7d04SAleksandr Rybalko * documentation and/or other materials provided with the distribution.
1727cf7d04SAleksandr Rybalko *
1827cf7d04SAleksandr Rybalko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1927cf7d04SAleksandr Rybalko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2027cf7d04SAleksandr Rybalko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2127cf7d04SAleksandr Rybalko * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2227cf7d04SAleksandr Rybalko * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2327cf7d04SAleksandr Rybalko * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2427cf7d04SAleksandr Rybalko * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2527cf7d04SAleksandr Rybalko * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2627cf7d04SAleksandr Rybalko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2727cf7d04SAleksandr Rybalko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2827cf7d04SAleksandr Rybalko * SUCH DAMAGE.
2927cf7d04SAleksandr Rybalko */
3027cf7d04SAleksandr Rybalko
3127cf7d04SAleksandr Rybalko #include <sys/param.h>
3227cf7d04SAleksandr Rybalko #include <sys/kernel.h>
3327cf7d04SAleksandr Rybalko #include <sys/malloc.h>
3427cf7d04SAleksandr Rybalko #include <sys/refcount.h>
3527cf7d04SAleksandr Rybalko #include <sys/systm.h>
3627cf7d04SAleksandr Rybalko
3727cf7d04SAleksandr Rybalko #include <dev/vt/vt.h>
3827cf7d04SAleksandr Rybalko
3927cf7d04SAleksandr Rybalko static MALLOC_DEFINE(M_VTFONT, "vtfont", "vt font");
4027cf7d04SAleksandr Rybalko
4127cf7d04SAleksandr Rybalko /* Some limits to prevent abnormal fonts from being loaded. */
42a04eaf90SEd Maste #define VTFONT_MAXMAPPINGS 65536
439f6fffc7SGordon Tetlow #define VTFONT_MAXGLYPHS 131072
44a04eaf90SEd Maste #define VTFONT_MAXGLYPHSIZE 2097152
4527cf7d04SAleksandr Rybalko #define VTFONT_MAXDIMENSION 128
4627cf7d04SAleksandr Rybalko
4727cf7d04SAleksandr Rybalko static uint16_t
vtfont_bisearch(const vfnt_map_t * map,unsigned int len,uint32_t src)48e7fd9688SToomas Soome vtfont_bisearch(const vfnt_map_t *map, unsigned int len, uint32_t src)
4927cf7d04SAleksandr Rybalko {
5027cf7d04SAleksandr Rybalko int min, mid, max;
5127cf7d04SAleksandr Rybalko
5227cf7d04SAleksandr Rybalko min = 0;
5327cf7d04SAleksandr Rybalko max = len - 1;
5427cf7d04SAleksandr Rybalko
5527cf7d04SAleksandr Rybalko /* Empty font map. */
5627cf7d04SAleksandr Rybalko if (len == 0)
5727cf7d04SAleksandr Rybalko return (0);
5827cf7d04SAleksandr Rybalko /* Character below minimal entry. */
5927cf7d04SAleksandr Rybalko if (src < map[0].vfm_src)
6027cf7d04SAleksandr Rybalko return (0);
6127cf7d04SAleksandr Rybalko /* Optimization: ASCII characters occur very often. */
6227cf7d04SAleksandr Rybalko if (src <= map[0].vfm_src + map[0].vfm_len)
6327cf7d04SAleksandr Rybalko return (src - map[0].vfm_src + map[0].vfm_dst);
6427cf7d04SAleksandr Rybalko /* Character above maximum entry. */
6527cf7d04SAleksandr Rybalko if (src > map[max].vfm_src + map[max].vfm_len)
6627cf7d04SAleksandr Rybalko return (0);
6727cf7d04SAleksandr Rybalko
6827cf7d04SAleksandr Rybalko /* Binary search. */
6927cf7d04SAleksandr Rybalko while (max >= min) {
7027cf7d04SAleksandr Rybalko mid = (min + max) / 2;
7127cf7d04SAleksandr Rybalko if (src < map[mid].vfm_src)
7227cf7d04SAleksandr Rybalko max = mid - 1;
7327cf7d04SAleksandr Rybalko else if (src > map[mid].vfm_src + map[mid].vfm_len)
7427cf7d04SAleksandr Rybalko min = mid + 1;
7527cf7d04SAleksandr Rybalko else
7627cf7d04SAleksandr Rybalko return (src - map[mid].vfm_src + map[mid].vfm_dst);
7727cf7d04SAleksandr Rybalko }
7827cf7d04SAleksandr Rybalko
7927cf7d04SAleksandr Rybalko return (0);
8027cf7d04SAleksandr Rybalko }
8127cf7d04SAleksandr Rybalko
8227cf7d04SAleksandr Rybalko const uint8_t *
vtfont_lookup(const struct vt_font * vf,term_char_t c)8327cf7d04SAleksandr Rybalko vtfont_lookup(const struct vt_font *vf, term_char_t c)
8427cf7d04SAleksandr Rybalko {
8527cf7d04SAleksandr Rybalko uint32_t src;
8627cf7d04SAleksandr Rybalko uint16_t dst;
8727cf7d04SAleksandr Rybalko size_t stride;
8841fb0665SEd Maste unsigned int normal_map;
8941fb0665SEd Maste unsigned int bold_map;
9027cf7d04SAleksandr Rybalko
9127cf7d04SAleksandr Rybalko src = TCHAR_CHARACTER(c);
9241fb0665SEd Maste if (TCHAR_FORMAT(c) & TF_CJK_RIGHT) {
9341fb0665SEd Maste normal_map = VFNT_MAP_NORMAL_RIGHT;
9441fb0665SEd Maste bold_map = VFNT_MAP_BOLD_RIGHT;
9541fb0665SEd Maste } else {
9641fb0665SEd Maste normal_map = VFNT_MAP_NORMAL;
9741fb0665SEd Maste bold_map = VFNT_MAP_BOLD;
9841fb0665SEd Maste }
99a6c26592SEd Schouten
10027cf7d04SAleksandr Rybalko if (TCHAR_FORMAT(c) & TF_BOLD) {
10141fb0665SEd Maste dst = vtfont_bisearch(vf->vf_map[bold_map],
10241fb0665SEd Maste vf->vf_map_count[bold_map], src);
10327cf7d04SAleksandr Rybalko if (dst != 0)
10427cf7d04SAleksandr Rybalko goto found;
10527cf7d04SAleksandr Rybalko }
10641fb0665SEd Maste dst = vtfont_bisearch(vf->vf_map[normal_map],
10741fb0665SEd Maste vf->vf_map_count[normal_map], src);
10827cf7d04SAleksandr Rybalko
10927cf7d04SAleksandr Rybalko found:
11027cf7d04SAleksandr Rybalko stride = howmany(vf->vf_width, 8) * vf->vf_height;
11127cf7d04SAleksandr Rybalko return (&vf->vf_bytes[dst * stride]);
11227cf7d04SAleksandr Rybalko }
11327cf7d04SAleksandr Rybalko
11427cf7d04SAleksandr Rybalko struct vt_font *
vtfont_ref(struct vt_font * vf)11527cf7d04SAleksandr Rybalko vtfont_ref(struct vt_font *vf)
11627cf7d04SAleksandr Rybalko {
11727cf7d04SAleksandr Rybalko
11827cf7d04SAleksandr Rybalko refcount_acquire(&vf->vf_refcount);
11927cf7d04SAleksandr Rybalko return (vf);
12027cf7d04SAleksandr Rybalko }
12127cf7d04SAleksandr Rybalko
12227cf7d04SAleksandr Rybalko void
vtfont_unref(struct vt_font * vf)12327cf7d04SAleksandr Rybalko vtfont_unref(struct vt_font *vf)
12427cf7d04SAleksandr Rybalko {
12541fb0665SEd Maste unsigned int i;
12627cf7d04SAleksandr Rybalko
12727cf7d04SAleksandr Rybalko if (refcount_release(&vf->vf_refcount)) {
12841fb0665SEd Maste for (i = 0; i < VFNT_MAPS; i++)
12941fb0665SEd Maste free(vf->vf_map[i], M_VTFONT);
13027cf7d04SAleksandr Rybalko free(vf->vf_bytes, M_VTFONT);
13127cf7d04SAleksandr Rybalko free(vf, M_VTFONT);
13227cf7d04SAleksandr Rybalko }
13327cf7d04SAleksandr Rybalko }
13427cf7d04SAleksandr Rybalko
13527cf7d04SAleksandr Rybalko static int
vtfont_validate_map(vfnt_map_t * vfm,unsigned int length,unsigned int glyph_count)136e7fd9688SToomas Soome vtfont_validate_map(vfnt_map_t *vfm, unsigned int length,
13741fb0665SEd Maste unsigned int glyph_count)
13827cf7d04SAleksandr Rybalko {
13927cf7d04SAleksandr Rybalko unsigned int i, last = 0;
14027cf7d04SAleksandr Rybalko
14127cf7d04SAleksandr Rybalko for (i = 0; i < length; i++) {
14227cf7d04SAleksandr Rybalko /* Not ordered. */
14327cf7d04SAleksandr Rybalko if (i > 0 && vfm[i].vfm_src <= last)
14427cf7d04SAleksandr Rybalko return (EINVAL);
14527cf7d04SAleksandr Rybalko /*
14627cf7d04SAleksandr Rybalko * Destination extends amount of glyphs.
14727cf7d04SAleksandr Rybalko */
14841fb0665SEd Maste if (vfm[i].vfm_dst >= glyph_count ||
14941fb0665SEd Maste vfm[i].vfm_dst + vfm[i].vfm_len >= glyph_count)
15027cf7d04SAleksandr Rybalko return (EINVAL);
15127cf7d04SAleksandr Rybalko last = vfm[i].vfm_src + vfm[i].vfm_len;
15227cf7d04SAleksandr Rybalko }
15327cf7d04SAleksandr Rybalko
15427cf7d04SAleksandr Rybalko return (0);
15527cf7d04SAleksandr Rybalko }
15627cf7d04SAleksandr Rybalko
15727cf7d04SAleksandr Rybalko int
vtfont_load(vfnt_t * f,struct vt_font ** ret)15827cf7d04SAleksandr Rybalko vtfont_load(vfnt_t *f, struct vt_font **ret)
15927cf7d04SAleksandr Rybalko {
16041fb0665SEd Maste size_t glyphsize, mapsize;
16127cf7d04SAleksandr Rybalko struct vt_font *vf;
16227cf7d04SAleksandr Rybalko int error;
16341fb0665SEd Maste unsigned int i;
16427cf7d04SAleksandr Rybalko
16527cf7d04SAleksandr Rybalko /* Make sure the dimensions are valid. */
16627cf7d04SAleksandr Rybalko if (f->width < 1 || f->height < 1)
16727cf7d04SAleksandr Rybalko return (EINVAL);
1689f6fffc7SGordon Tetlow if (f->width > VTFONT_MAXDIMENSION || f->height > VTFONT_MAXDIMENSION ||
1699f6fffc7SGordon Tetlow f->glyph_count > VTFONT_MAXGLYPHS)
17027cf7d04SAleksandr Rybalko return (E2BIG);
17127cf7d04SAleksandr Rybalko
17227cf7d04SAleksandr Rybalko /* Not too many mappings. */
17341fb0665SEd Maste for (i = 0; i < VFNT_MAPS; i++)
17441fb0665SEd Maste if (f->map_count[i] > VTFONT_MAXMAPPINGS)
17527cf7d04SAleksandr Rybalko return (E2BIG);
17627cf7d04SAleksandr Rybalko
17727cf7d04SAleksandr Rybalko /* Character 0 must always be present. */
17841fb0665SEd Maste if (f->glyph_count < 1)
17927cf7d04SAleksandr Rybalko return (EINVAL);
18027cf7d04SAleksandr Rybalko
18141fb0665SEd Maste glyphsize = howmany(f->width, 8) * f->height * f->glyph_count;
18227cf7d04SAleksandr Rybalko if (glyphsize > VTFONT_MAXGLYPHSIZE)
18327cf7d04SAleksandr Rybalko return (E2BIG);
18427cf7d04SAleksandr Rybalko
18527cf7d04SAleksandr Rybalko /* Allocate new font structure. */
18641fb0665SEd Maste vf = malloc(sizeof *vf, M_VTFONT, M_WAITOK | M_ZERO);
18727cf7d04SAleksandr Rybalko vf->vf_bytes = malloc(glyphsize, M_VTFONT, M_WAITOK);
18827cf7d04SAleksandr Rybalko vf->vf_height = f->height;
18927cf7d04SAleksandr Rybalko vf->vf_width = f->width;
19027cf7d04SAleksandr Rybalko vf->vf_refcount = 1;
19127cf7d04SAleksandr Rybalko
19241fb0665SEd Maste /* Allocate, copy in, and validate mappings. */
19341fb0665SEd Maste for (i = 0; i < VFNT_MAPS; i++) {
19441fb0665SEd Maste vf->vf_map_count[i] = f->map_count[i];
19541fb0665SEd Maste if (f->map_count[i] == 0)
19641fb0665SEd Maste continue;
197e7fd9688SToomas Soome mapsize = f->map_count[i] * sizeof(vfnt_map_t);
19841fb0665SEd Maste vf->vf_map[i] = malloc(mapsize, M_VTFONT, M_WAITOK);
19941fb0665SEd Maste error = copyin(f->map[i], vf->vf_map[i], mapsize);
20027cf7d04SAleksandr Rybalko if (error)
20127cf7d04SAleksandr Rybalko goto bad;
20241fb0665SEd Maste error = vtfont_validate_map(vf->vf_map[i], vf->vf_map_count[i],
20341fb0665SEd Maste f->glyph_count);
20427cf7d04SAleksandr Rybalko if (error)
20527cf7d04SAleksandr Rybalko goto bad;
20641fb0665SEd Maste }
20727cf7d04SAleksandr Rybalko
20841fb0665SEd Maste /* Copy in glyph data. */
20941fb0665SEd Maste error = copyin(f->glyphs, vf->vf_bytes, glyphsize);
21027cf7d04SAleksandr Rybalko if (error)
21127cf7d04SAleksandr Rybalko goto bad;
21227cf7d04SAleksandr Rybalko
21327cf7d04SAleksandr Rybalko /* Success. */
21427cf7d04SAleksandr Rybalko *ret = vf;
21527cf7d04SAleksandr Rybalko return (0);
21627cf7d04SAleksandr Rybalko
21727cf7d04SAleksandr Rybalko bad: vtfont_unref(vf);
21827cf7d04SAleksandr Rybalko return (error);
21927cf7d04SAleksandr Rybalko }
220