1219888Sed/*- 2219888Sed * Copyright (c) 2009 The FreeBSD Foundation 3219888Sed * All rights reserved. 4219888Sed * 5219888Sed * This software was developed by Ed Schouten under sponsorship from the 6219888Sed * FreeBSD Foundation. 7219888Sed * 8219888Sed * Redistribution and use in source and binary forms, with or without 9219888Sed * modification, are permitted provided that the following conditions 10219888Sed * are met: 11219888Sed * 1. Redistributions of source code must retain the above copyright 12219888Sed * notice, this list of conditions and the following disclaimer. 13219888Sed * 2. Redistributions in binary form must reproduce the above copyright 14219888Sed * notice, this list of conditions and the following disclaimer in the 15219888Sed * documentation and/or other materials provided with the distribution. 16219888Sed * 17219888Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18219888Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19219888Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20219888Sed * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21219888Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22219888Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23219888Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24219888Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25219888Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26219888Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27219888Sed * SUCH DAMAGE. 28219888Sed */ 29219888Sed 30219888Sed#include <sys/cdefs.h> 31219888Sed__FBSDID("$FreeBSD: stable/11/sys/dev/vt/vt_font.c 353926 2019-10-23 14:16:34Z emaste $"); 32219888Sed 33219888Sed#include <sys/param.h> 34219888Sed#include <sys/kernel.h> 35219888Sed#include <sys/malloc.h> 36219888Sed#include <sys/refcount.h> 37219888Sed#include <sys/systm.h> 38219888Sed 39219888Sed#include <dev/vt/vt.h> 40219888Sed 41219888Sedstatic MALLOC_DEFINE(M_VTFONT, "vtfont", "vt font"); 42219888Sed 43219888Sed/* Some limits to prevent abnormal fonts from being loaded. */ 44281537Semaste#define VTFONT_MAXMAPPINGS 65536 45331982Sgordon#define VTFONT_MAXGLYPHS 131072 46281537Semaste#define VTFONT_MAXGLYPHSIZE 2097152 47219888Sed#define VTFONT_MAXDIMENSION 128 48219888Sed 49219888Sedstatic uint16_t 50219888Sedvtfont_bisearch(const struct vt_font_map *map, unsigned int len, uint32_t src) 51219888Sed{ 52219888Sed int min, mid, max; 53219888Sed 54219888Sed min = 0; 55219888Sed max = len - 1; 56219888Sed 57219888Sed /* Empty font map. */ 58219888Sed if (len == 0) 59219888Sed return (0); 60219888Sed /* Character below minimal entry. */ 61219888Sed if (src < map[0].vfm_src) 62219888Sed return (0); 63219888Sed /* Optimization: ASCII characters occur very often. */ 64219888Sed if (src <= map[0].vfm_src + map[0].vfm_len) 65219888Sed return (src - map[0].vfm_src + map[0].vfm_dst); 66219888Sed /* Character above maximum entry. */ 67219888Sed if (src > map[max].vfm_src + map[max].vfm_len) 68219888Sed return (0); 69219888Sed 70219888Sed /* Binary search. */ 71219888Sed while (max >= min) { 72219888Sed mid = (min + max) / 2; 73219888Sed if (src < map[mid].vfm_src) 74219888Sed max = mid - 1; 75219888Sed else if (src > map[mid].vfm_src + map[mid].vfm_len) 76219888Sed min = mid + 1; 77219888Sed else 78219888Sed return (src - map[mid].vfm_src + map[mid].vfm_dst); 79219888Sed } 80219888Sed 81219888Sed return (0); 82219888Sed} 83219888Sed 84219888Sedconst uint8_t * 85219888Sedvtfont_lookup(const struct vt_font *vf, term_char_t c) 86219888Sed{ 87219888Sed uint32_t src; 88219888Sed uint16_t dst; 89219888Sed size_t stride; 90259680Semaste unsigned int normal_map; 91259680Semaste unsigned int bold_map; 92219888Sed 93219888Sed src = TCHAR_CHARACTER(c); 94259680Semaste if (TCHAR_FORMAT(c) & TF_CJK_RIGHT) { 95259680Semaste normal_map = VFNT_MAP_NORMAL_RIGHT; 96259680Semaste bold_map = VFNT_MAP_BOLD_RIGHT; 97259680Semaste } else { 98259680Semaste normal_map = VFNT_MAP_NORMAL; 99259680Semaste bold_map = VFNT_MAP_BOLD; 100259680Semaste } 101259667Sed 102219888Sed if (TCHAR_FORMAT(c) & TF_BOLD) { 103259680Semaste dst = vtfont_bisearch(vf->vf_map[bold_map], 104259680Semaste vf->vf_map_count[bold_map], src); 105219888Sed if (dst != 0) 106219888Sed goto found; 107219888Sed } 108259680Semaste dst = vtfont_bisearch(vf->vf_map[normal_map], 109259680Semaste vf->vf_map_count[normal_map], src); 110219888Sed 111219888Sedfound: 112219888Sed stride = howmany(vf->vf_width, 8) * vf->vf_height; 113219888Sed return (&vf->vf_bytes[dst * stride]); 114219888Sed} 115219888Sed 116219888Sedstruct vt_font * 117219888Sedvtfont_ref(struct vt_font *vf) 118219888Sed{ 119219888Sed 120219888Sed refcount_acquire(&vf->vf_refcount); 121219888Sed return (vf); 122219888Sed} 123219888Sed 124219888Sedvoid 125219888Sedvtfont_unref(struct vt_font *vf) 126219888Sed{ 127259680Semaste unsigned int i; 128219888Sed 129219888Sed if (refcount_release(&vf->vf_refcount)) { 130259680Semaste for (i = 0; i < VFNT_MAPS; i++) 131259680Semaste free(vf->vf_map[i], M_VTFONT); 132219888Sed free(vf->vf_bytes, M_VTFONT); 133219888Sed free(vf, M_VTFONT); 134219888Sed } 135219888Sed} 136219888Sed 137219888Sedstatic int 138219888Sedvtfont_validate_map(struct vt_font_map *vfm, unsigned int length, 139259680Semaste unsigned int glyph_count) 140219888Sed{ 141219888Sed unsigned int i, last = 0; 142219888Sed 143219888Sed for (i = 0; i < length; i++) { 144219888Sed /* Not ordered. */ 145219888Sed if (i > 0 && vfm[i].vfm_src <= last) 146219888Sed return (EINVAL); 147219888Sed /* 148219888Sed * Destination extends amount of glyphs. 149219888Sed */ 150259680Semaste if (vfm[i].vfm_dst >= glyph_count || 151259680Semaste vfm[i].vfm_dst + vfm[i].vfm_len >= glyph_count) 152219888Sed return (EINVAL); 153219888Sed last = vfm[i].vfm_src + vfm[i].vfm_len; 154219888Sed } 155219888Sed 156219888Sed return (0); 157219888Sed} 158219888Sed 159219888Sedint 160219888Sedvtfont_load(vfnt_t *f, struct vt_font **ret) 161219888Sed{ 162259680Semaste size_t glyphsize, mapsize; 163219888Sed struct vt_font *vf; 164219888Sed int error; 165259680Semaste unsigned int i; 166219888Sed 167219888Sed /* Make sure the dimensions are valid. */ 168219888Sed if (f->width < 1 || f->height < 1) 169219888Sed return (EINVAL); 170331982Sgordon if (f->width > VTFONT_MAXDIMENSION || f->height > VTFONT_MAXDIMENSION || 171331982Sgordon f->glyph_count > VTFONT_MAXGLYPHS) 172219888Sed return (E2BIG); 173219888Sed 174219888Sed /* Not too many mappings. */ 175259680Semaste for (i = 0; i < VFNT_MAPS; i++) 176259680Semaste if (f->map_count[i] > VTFONT_MAXMAPPINGS) 177259680Semaste return (E2BIG); 178256145Sray 179219888Sed /* Character 0 must always be present. */ 180259680Semaste if (f->glyph_count < 1) 181219888Sed return (EINVAL); 182219888Sed 183259680Semaste glyphsize = howmany(f->width, 8) * f->height * f->glyph_count; 184219888Sed if (glyphsize > VTFONT_MAXGLYPHSIZE) 185219888Sed return (E2BIG); 186219888Sed 187219888Sed /* Allocate new font structure. */ 188259680Semaste vf = malloc(sizeof *vf, M_VTFONT, M_WAITOK | M_ZERO); 189219888Sed vf->vf_bytes = malloc(glyphsize, M_VTFONT, M_WAITOK); 190219888Sed vf->vf_height = f->height; 191219888Sed vf->vf_width = f->width; 192219888Sed vf->vf_refcount = 1; 193219888Sed 194259680Semaste /* Allocate, copy in, and validate mappings. */ 195259680Semaste for (i = 0; i < VFNT_MAPS; i++) { 196259680Semaste vf->vf_map_count[i] = f->map_count[i]; 197259680Semaste if (f->map_count[i] == 0) 198259680Semaste continue; 199259680Semaste mapsize = f->map_count[i] * sizeof(struct vt_font_map); 200259680Semaste vf->vf_map[i] = malloc(mapsize, M_VTFONT, M_WAITOK); 201259680Semaste error = copyin(f->map[i], vf->vf_map[i], mapsize); 202259680Semaste if (error) 203259680Semaste goto bad; 204259680Semaste error = vtfont_validate_map(vf->vf_map[i], vf->vf_map_count[i], 205259680Semaste f->glyph_count); 206259680Semaste if (error) 207259680Semaste goto bad; 208259680Semaste } 209259680Semaste 210259680Semaste /* Copy in glyph data. */ 211219888Sed error = copyin(f->glyphs, vf->vf_bytes, glyphsize); 212219888Sed if (error) 213219888Sed goto bad; 214219888Sed 215219888Sed /* Success. */ 216219888Sed *ret = vf; 217219888Sed return (0); 218219888Sed 219219888Sedbad: vtfont_unref(vf); 220219888Sed return (error); 221219888Sed} 222