// SPDX-License-Identifier: GPL-2.0 /* * consolemap.c * * Mapping from internal code (such as Latin-1 or Unicode or IBM PC code) * to font positions. * * aeb, 950210 * * Support for multiple unimaps by Jakub Jelinek <jj@ultra.linux.cz>, July 1998 * * Fix bug in inverse translation. Stanislav Voronyi <stas@cnti.uanet.kharkov.ua>, Dec 1998 * * In order to prevent the following circular lock dependency: * &mm->mmap_lock --> cpu_hotplug.lock --> console_lock --> &mm->mmap_lock * * We cannot allow page fault to happen while holding the console_lock. * Therefore, all the userspace copy operations have to be done outside * the console_lock critical sections. * * As all the affected functions are all called directly from vt_ioctl(), we * can allocate some small buffers directly on stack without worrying about * stack overflow.
*/
for (d = 0; d < UNI_DIRS; d++) {
u16 **dir = dict->uni_pgdir[d]; if (!dir) continue; for (r = 0; r < UNI_DIR_ROWS; r++) {
u16 *row = dir[r]; if (!row) continue; for (g = 0; g < UNI_ROW_GLYPHS; g++) {
u16 glyph = row[g]; if (glyph < MAX_GLYPH && inv[glyph] < 32)
inv[glyph] = UNI(d, r, g);
}
}
}
}
unsignedshort *set_translate(enum translation_map m, struct vc_data *vc)
{
inv_translate[vc->vc_num] = m; return translations[m];
}
/* * Inverse translation is impossible for several reasons: * 1. The font<->character maps are not 1-1. * 2. The text may have been written while a different translation map * was active. * Still, it is now possible to a certain extent to cut and paste non-ASCII.
*/
u16 inverse_translate(conststruct vc_data *conp, u16 glyph, bool use_unicode)
{ struct uni_pagedict *p; enum translation_map m;
if (glyph >= MAX_GLYPH) return 0;
p = *conp->uni_pagedict_loc; if (!p) return glyph;
if (use_unicode) { if (!p->inverse_trans_unicode) return glyph;
return p->inverse_trans_unicode[glyph];
}
m = inv_translate[conp->vc_num]; if (!p->inverse_translations[m]) return glyph;
for (i = 0; i < MAX_NR_CONSOLES; i++) { if (!vc_cons_allocated(i)) continue;
p = *vc_cons[i].d->uni_pagedict_loc; if (p && p != q) {
set_inverse_transl(vc_cons[i].d, p, USER_MAP);
set_inverse_trans_unicode(p);
q = p;
}
}
}
/* * Load customizable translation table * arg points to a 256 byte translation table. * * The "old" variants are for translation directly to font (using the * 0xf000-0xf0ff "transparent" Unicodes) whereas the "new" variants set * Unicodes explicitly.
*/ int con_set_trans_old(unsignedchar __user * arg)
{ unsignedshort inbuf[E_TABSZ]; unsignedint i; unsignedchar ch;
for (i = 0; i < ARRAY_SIZE(inbuf); i++) { if (get_user(ch, &arg[i])) return -EFAULT;
inbuf[i] = UNI_DIRECT_BASE | ch;
}
/* * Unicode -> current font conversion * * A font has at most 512 chars, usually 256. * But one font position may represent several Unicode chars. * A hashtable is somewhat of a pain to deal with, so use a * "paged table" instead. Simulation has shown the memory cost of * this 3-level paged table scheme to be comparable to a hash table.
*/
extern u8 dfont_unicount[]; /* Defined in console_defmap.c */ extern u16 dfont_unitable[];
n = UNI_DIR(unicode);
dir = p->uni_pgdir[n]; if (!dir) {
dir = p->uni_pgdir[n] = kcalloc(UNI_DIR_ROWS, sizeof(*dir),
GFP_KERNEL); if (!dir) return -ENOMEM;
}
n = UNI_ROW(unicode);
row = dir[n]; if (!row) {
row = dir[n] = kmalloc_array(UNI_ROW_GLYPHS, sizeof(*row),
GFP_KERNEL); if (!row) return -ENOMEM; /* No glyphs for the characters (yet) */
memset(row, 0xff, UNI_ROW_GLYPHS * sizeof(*row));
}
ret = con_allocate_new(vc); if (ret) return ERR_PTR(ret);
new = *vc->uni_pagedict_loc;
/* * uni_pgdir is a 32*32*64 table with rows allocated when its first * entry is added. The unicode value must still be incremented for * empty rows. We are copying entries from "old" to "new".
*/ for (d = 0; d < UNI_DIRS; d++) {
u16 **dir = old->uni_pgdir[d]; if (!dir) { /* Account for empty table */
uni += UNI_DIR_ROWS * UNI_ROW_GLYPHS; continue;
}
for (r = 0; r < UNI_DIR_ROWS; r++) {
u16 *row = dir[r]; if (!row) { /* Account for row of 64 empty entries */
uni += UNI_ROW_GLYPHS; continue;
}
for (g = 0; g < UNI_ROW_GLYPHS; g++, uni++) { if (row[g] == 0xffff) continue; /* * Found one, copy entry for unicode uni with * fontpos value row[g].
*/
ret = con_insert_unipair(new, uni, row[g]); if (ret) {
old->refcount++;
*vc->uni_pagedict_loc = old;
con_release_unimap(new);
kfree(new); return ERR_PTR(ret);
}
}
}
}
/** * con_set_default_unimap - set default unicode map * @vc: the console we are updating * * Loads the unimap for the hardware font, as defined in uni_hash.tbl. * The representation used was the most compact I could come up * with. This routine is executed at video setup, and when the * PIO_FONTRESET ioctl is called. * * The caller must hold the console lock
*/ int con_set_default_unimap(struct vc_data *vc)
{ struct uni_pagedict *dict; unsignedint fontpos, count; int err = 0, err1;
u16 *dfont;
if (dflt) {
dict = *vc->uni_pagedict_loc; if (dict == dflt) return 0;
for (fontpos = 0; fontpos < 256U; fontpos++) for (count = dfont_unicount[fontpos]; count; count--) {
err1 = con_insert_unipair(dict, *(dfont++), fontpos); if (err1)
err = err1;
}
if (con_unify_unimap(vc, dict)) {
dflt = *vc->uni_pagedict_loc; return err;
}
for (enum translation_map m = FIRST_MAP; m <= LAST_MAP; m++)
set_inverse_transl(vc, dict, m);
set_inverse_trans_unicode(dict);
dflt = dict; return err;
}
EXPORT_SYMBOL(con_set_default_unimap);
/** * con_copy_unimap - copy unimap between two vts * @dst_vc: target * @src_vc: source * * The caller must hold the console lock when invoking this method
*/ int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
{ struct uni_pagedict *src;
/* * con_get_unimap - get the unicode map * * Read the console unicode data for this console. Called from the ioctl * handlers.
*/ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list)
{
ushort ect; struct uni_pagedict *dict; struct unipair *unilist; unsignedint d, r, g; int ret = 0;
unilist = kvmalloc_array(ct, sizeof(*unilist), GFP_KERNEL); if (!unilist) return -ENOMEM;
console_lock();
ect = 0;
dict = *vc->uni_pagedict_loc; if (!dict) goto unlock;
for (d = 0; d < UNI_DIRS; d++) {
u16 **dir = dict->uni_pgdir[d]; if (!dir) continue;
for (r = 0; r < UNI_DIR_ROWS; r++) {
u16 *row = dir[r]; if (!row) continue;
for (g = 0; g < UNI_ROW_GLYPHS; g++, row++) { if (*row >= MAX_GLYPH) continue; if (ect < ct) {
unilist[ect].unicode = UNI(d, r, g);
unilist[ect].fontpos = *row;
}
ect++;
}
}
}
unlock:
console_unlock(); if (copy_to_user(list, unilist, min(ect, ct) * sizeof(*unilist)))
ret = -EFAULT; if (put_user(ect, uct))
ret = -EFAULT;
kvfree(unilist); return ret ? ret : (ect <= ct) ? 0 : -ENOMEM;
}
/* * Always use USER_MAP. These functions are used by the keyboard, * which shouldn't be affected by G0/G1 switching, etc. * If the user map still contains default values, i.e. the * direct-to-font mapping, then assume user is using Latin1. * * FIXME: at some point we need to decide if we want to lock the table * update element itself via the keyboard_event_lock for consistency with the * keyboard driver as well as the consoles
*/ /* may be called during an interrupt */
u32 conv_8bit_to_uni(unsignedchar c)
{ unsignedshort uni = translations[USER_MAP][c]; return uni == (0xf000 | c) ? c : uni;
}
int conv_uni_to_8bit(u32 uni)
{ int c; for (c = 0; c < ARRAY_SIZE(translations[USER_MAP]); c++) if (translations[USER_MAP][c] == uni ||
(translations[USER_MAP][c] == (c | 0xf000) && uni == c)) return c; return -1;
}
int conv_uni_to_pc(struct vc_data *conp, long ucs)
{ struct uni_pagedict *dict;
u16 **dir, *row, glyph;
/* Only 16-bit codes supported at this time */ if (ucs > 0xffff) return -4; /* Not found */ elseif (ucs < 0x20) return -1; /* Not a printable character */ /* * UNI_DIRECT_BASE indicates the start of the region in the User Zone * which always has a 1:1 mapping to the currently loaded font. The * UNI_DIRECT_MASK indicates the bit span of the region.
*/ elseif ((ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE) return ucs & UNI_DIRECT_MASK;
dict = *conp->uni_pagedict_loc; if (!dict) return -3;
dir = dict->uni_pgdir[UNI_DIR(ucs)]; if (!dir) return -4;
row = dir[UNI_ROW(ucs)]; if (!row) return -4;
glyph = row[UNI_GLYPH(ucs)]; if (glyph >= MAX_GLYPH) return -4;
return glyph;
}
/* * This is called at sys_setup time, after memory and the console are * initialized. It must be possible to call kmalloc(..., GFP_KERNEL) * from this function, hence the call from sys_setup.
*/ void __init
console_map_init(void)
{ int i;
for (i = 0; i < MAX_NR_CONSOLES; i++) if (vc_cons_allocated(i) && !*vc_cons[i].d->uni_pagedict_loc)
con_set_default_unimap(vc_cons[i].d);
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.16 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.