// 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 .
*/
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/module.h>
#include <linux/kd.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/tty.h>
#include <linux/uaccess.h>
#include <linux/console.h>
#include <linux/consolemap.h>
#include <linux/vt_kern.h>
#include <linux/string.h>
static unsigned short translations[][E_TABSZ] = {
/* 8-bit Latin-1 mapped to Unicode -- trivial mapping */
[LAT1_MAP] = {
0 x0000, 0 x0001, 0 x0002, 0 x0003, 0 x0004, 0 x0005, 0 x0006, 0 x0007,
0 x0008, 0 x0009, 0 x000a, 0 x000b, 0 x000c, 0 x000d, 0 x000e, 0 x000f,
0 x0010, 0 x0011, 0 x0012, 0 x0013, 0 x0014, 0 x0015, 0 x0016, 0 x0017,
0 x0018, 0 x0019, 0 x001a, 0 x001b, 0 x001c, 0 x001d, 0 x001e, 0 x001f,
0 x0020, 0 x0021, 0 x0022, 0 x0023, 0 x0024, 0 x0025, 0 x0026, 0 x0027,
0 x0028, 0 x0029, 0 x002a, 0 x002b, 0 x002c, 0 x002d, 0 x002e, 0 x002f,
0 x0030, 0 x0031, 0 x0032, 0 x0033, 0 x0034, 0 x0035, 0 x0036, 0 x0037,
0 x0038, 0 x0039, 0 x003a, 0 x003b, 0 x003c, 0 x003d, 0 x003e, 0 x003f,
0 x0040, 0 x0041, 0 x0042, 0 x0043, 0 x0044, 0 x0045, 0 x0046, 0 x0047,
0 x0048, 0 x0049, 0 x004a, 0 x004b, 0 x004c, 0 x004d, 0 x004e, 0 x004f,
0 x0050, 0 x0051, 0 x0052, 0 x0053, 0 x0054, 0 x0055, 0 x0056, 0 x0057,
0 x0058, 0 x0059, 0 x005a, 0 x005b, 0 x005c, 0 x005d, 0 x005e, 0 x005f,
0 x0060, 0 x0061, 0 x0062, 0 x0063, 0 x0064, 0 x0065, 0 x0066, 0 x0067,
0 x0068, 0 x0069, 0 x006a, 0 x006b, 0 x006c, 0 x006d, 0 x006e, 0 x006f,
0 x0070, 0 x0071, 0 x0072, 0 x0073, 0 x0074, 0 x0075, 0 x0076, 0 x0077,
0 x0078, 0 x0079, 0 x007a, 0 x007b, 0 x007c, 0 x007d, 0 x007e, 0 x007f,
0 x0080, 0 x0081, 0 x0082, 0 x0083, 0 x0084, 0 x0085, 0 x0086, 0 x0087,
0 x0088, 0 x0089, 0 x008a, 0 x008b, 0 x008c, 0 x008d, 0 x008e, 0 x008f,
0 x0090, 0 x0091, 0 x0092, 0 x0093, 0 x0094, 0 x0095, 0 x0096, 0 x0097,
0 x0098, 0 x0099, 0 x009a, 0 x009b, 0 x009c, 0 x009d, 0 x009e, 0 x009f,
0 x00a0, 0 x00a1, 0 x00a2, 0 x00a3, 0 x00a4, 0 x00a5, 0 x00a6, 0 x00a7,
0 x00a8, 0 x00a9, 0 x00aa, 0 x00ab, 0 x00ac, 0 x00ad, 0 x00ae, 0 x00af,
0 x00b0, 0 x00b1, 0 x00b2, 0 x00b3, 0 x00b4, 0 x00b5, 0 x00b6, 0 x00b7,
0 x00b8, 0 x00b9, 0 x00ba, 0 x00bb, 0 x00bc, 0 x00bd, 0 x00be, 0 x00bf,
0 x00c0, 0 x00c1, 0 x00c2, 0 x00c3, 0 x00c4, 0 x00c5, 0 x00c6, 0 x00c7,
0 x00c8, 0 x00c9, 0 x00ca, 0 x00cb, 0 x00cc, 0 x00cd, 0 x00ce, 0 x00cf,
0 x00d0, 0 x00d1, 0 x00d2, 0 x00d3, 0 x00d4, 0 x00d5, 0 x00d6, 0 x00d7,
0 x00d8, 0 x00d9, 0 x00da, 0 x00db, 0 x00dc, 0 x00dd, 0 x00de, 0 x00df,
0 x00e0, 0 x00e1, 0 x00e2, 0 x00e3, 0 x00e4, 0 x00e5, 0 x00e6, 0 x00e7,
0 x00e8, 0 x00e9, 0 x00ea, 0 x00eb, 0 x00ec, 0 x00ed, 0 x00ee, 0 x00ef,
0 x00f0, 0 x00f1, 0 x00f2, 0 x00f3, 0 x00f4, 0 x00f5, 0 x00f6, 0 x00f7,
0 x00f8, 0 x00f9, 0 x00fa, 0 x00fb, 0 x00fc, 0 x00fd, 0 x00fe, 0 x00ff
},
/* VT100 graphics mapped to Unicode */
[GRAF_MAP] = {
0 x0000, 0 x0001, 0 x0002, 0 x0003, 0 x0004, 0 x0005, 0 x0006, 0 x0007,
0 x0008, 0 x0009, 0 x000a, 0 x000b, 0 x000c, 0 x000d, 0 x000e, 0 x000f,
0 x0010, 0 x0011, 0 x0012, 0 x0013, 0 x0014, 0 x0015, 0 x0016, 0 x0017,
0 x0018, 0 x0019, 0 x001a, 0 x001b, 0 x001c, 0 x001d, 0 x001e, 0 x001f,
0 x0020, 0 x0021, 0 x0022, 0 x0023, 0 x0024, 0 x0025, 0 x0026, 0 x0027,
0 x0028, 0 x0029, 0 x002a, 0 x2192, 0 x2190, 0 x2191, 0 x2193, 0 x002f,
0 x2588, 0 x0031, 0 x0032, 0 x0033, 0 x0034, 0 x0035, 0 x0036, 0 x0037,
0 x0038, 0 x0039, 0 x003a, 0 x003b, 0 x003c, 0 x003d, 0 x003e, 0 x003f,
0 x0040, 0 x0041, 0 x0042, 0 x0043, 0 x0044, 0 x0045, 0 x0046, 0 x0047,
0 x0048, 0 x0049, 0 x004a, 0 x004b, 0 x004c, 0 x004d, 0 x004e, 0 x004f,
0 x0050, 0 x0051, 0 x0052, 0 x0053, 0 x0054, 0 x0055, 0 x0056, 0 x0057,
0 x0058, 0 x0059, 0 x005a, 0 x005b, 0 x005c, 0 x005d, 0 x005e, 0 x00a0,
0 x25c6, 0 x2592, 0 x2409, 0 x240c, 0 x240d, 0 x240a, 0 x00b0, 0 x00b1,
0 x2591, 0 x240b, 0 x2518, 0 x2510, 0 x250c, 0 x2514, 0 x253c, 0 x23ba,
0 x23bb, 0 x2500, 0 x23bc, 0 x23bd, 0 x251c, 0 x2524, 0 x2534, 0 x252c,
0 x2502, 0 x2264, 0 x2265, 0 x03c0, 0 x2260, 0 x00a3, 0 x00b7, 0 x007f,
0 x0080, 0 x0081, 0 x0082, 0 x0083, 0 x0084, 0 x0085, 0 x0086, 0 x0087,
0 x0088, 0 x0089, 0 x008a, 0 x008b, 0 x008c, 0 x008d, 0 x008e, 0 x008f,
0 x0090, 0 x0091, 0 x0092, 0 x0093, 0 x0094, 0 x0095, 0 x0096, 0 x0097,
0 x0098, 0 x0099, 0 x009a, 0 x009b, 0 x009c, 0 x009d, 0 x009e, 0 x009f,
0 x00a0, 0 x00a1, 0 x00a2, 0 x00a3, 0 x00a4, 0 x00a5, 0 x00a6, 0 x00a7,
0 x00a8, 0 x00a9, 0 x00aa, 0 x00ab, 0 x00ac, 0 x00ad, 0 x00ae, 0 x00af,
0 x00b0, 0 x00b1, 0 x00b2, 0 x00b3, 0 x00b4, 0 x00b5, 0 x00b6, 0 x00b7,
0 x00b8, 0 x00b9, 0 x00ba, 0 x00bb, 0 x00bc, 0 x00bd, 0 x00be, 0 x00bf,
0 x00c0, 0 x00c1, 0 x00c2, 0 x00c3, 0 x00c4, 0 x00c5, 0 x00c6, 0 x00c7,
0 x00c8, 0 x00c9, 0 x00ca, 0 x00cb, 0 x00cc, 0 x00cd, 0 x00ce, 0 x00cf,
0 x00d0, 0 x00d1, 0 x00d2, 0 x00d3, 0 x00d4, 0 x00d5, 0 x00d6, 0 x00d7,
0 x00d8, 0 x00d9, 0 x00da, 0 x00db, 0 x00dc, 0 x00dd, 0 x00de, 0 x00df,
0 x00e0, 0 x00e1, 0 x00e2, 0 x00e3, 0 x00e4, 0 x00e5, 0 x00e6, 0 x00e7,
0 x00e8, 0 x00e9, 0 x00ea, 0 x00eb, 0 x00ec, 0 x00ed, 0 x00ee, 0 x00ef,
0 x00f0, 0 x00f1, 0 x00f2, 0 x00f3, 0 x00f4, 0 x00f5, 0 x00f6, 0 x00f7,
0 x00f8, 0 x00f9, 0 x00fa, 0 x00fb, 0 x00fc, 0 x00fd, 0 x00fe, 0 x00ff
},
/* IBM Codepage 437 mapped to Unicode */
[IBMPC_MAP] = {
0 x0000, 0 x263a, 0 x263b, 0 x2665, 0 x2666, 0 x2663, 0 x2660, 0 x2022,
0 x25d8, 0 x25cb, 0 x25d9, 0 x2642, 0 x2640, 0 x266a, 0 x266b, 0 x263c,
0 x25b6, 0 x25c0, 0 x2195, 0 x203c, 0 x00b6, 0 x00a7, 0 x25ac, 0 x21a8,
0 x2191, 0 x2193, 0 x2192, 0 x2190, 0 x221f, 0 x2194, 0 x25b2, 0 x25bc,
0 x0020, 0 x0021, 0 x0022, 0 x0023, 0 x0024, 0 x0025, 0 x0026, 0 x0027,
0 x0028, 0 x0029, 0 x002a, 0 x002b, 0 x002c, 0 x002d, 0 x002e, 0 x002f,
0 x0030, 0 x0031, 0 x0032, 0 x0033, 0 x0034, 0 x0035, 0 x0036, 0 x0037,
0 x0038, 0 x0039, 0 x003a, 0 x003b, 0 x003c, 0 x003d, 0 x003e, 0 x003f,
0 x0040, 0 x0041, 0 x0042, 0 x0043, 0 x0044, 0 x0045, 0 x0046, 0 x0047,
0 x0048, 0 x0049, 0 x004a, 0 x004b, 0 x004c, 0 x004d, 0 x004e, 0 x004f,
0 x0050, 0 x0051, 0 x0052, 0 x0053, 0 x0054, 0 x0055, 0 x0056, 0 x0057,
0 x0058, 0 x0059, 0 x005a, 0 x005b, 0 x005c, 0 x005d, 0 x005e, 0 x005f,
0 x0060, 0 x0061, 0 x0062, 0 x0063, 0 x0064, 0 x0065, 0 x0066, 0 x0067,
0 x0068, 0 x0069, 0 x006a, 0 x006b, 0 x006c, 0 x006d, 0 x006e, 0 x006f,
0 x0070, 0 x0071, 0 x0072, 0 x0073, 0 x0074, 0 x0075, 0 x0076, 0 x0077,
0 x0078, 0 x0079, 0 x007a, 0 x007b, 0 x007c, 0 x007d, 0 x007e, 0 x2302,
0 x00c7, 0 x00fc, 0 x00e9, 0 x00e2, 0 x00e4, 0 x00e0, 0 x00e5, 0 x00e7,
0 x00ea, 0 x00eb, 0 x00e8, 0 x00ef, 0 x00ee, 0 x00ec, 0 x00c4, 0 x00c5,
0 x00c9, 0 x00e6, 0 x00c6, 0 x00f4, 0 x00f6, 0 x00f2, 0 x00fb, 0 x00f9,
0 x00ff, 0 x00d6, 0 x00dc, 0 x00a2, 0 x00a3, 0 x00a5, 0 x20a7, 0 x0192,
0 x00e1, 0 x00ed, 0 x00f3, 0 x00fa, 0 x00f1, 0 x00d1, 0 x00aa, 0 x00ba,
0 x00bf, 0 x2310, 0 x00ac, 0 x00bd, 0 x00bc, 0 x00a1, 0 x00ab, 0 x00bb,
0 x2591, 0 x2592, 0 x2593, 0 x2502, 0 x2524, 0 x2561, 0 x2562, 0 x2556,
0 x2555, 0 x2563, 0 x2551, 0 x2557, 0 x255d, 0 x255c, 0 x255b, 0 x2510,
0 x2514, 0 x2534, 0 x252c, 0 x251c, 0 x2500, 0 x253c, 0 x255e, 0 x255f,
0 x255a, 0 x2554, 0 x2569, 0 x2566, 0 x2560, 0 x2550, 0 x256c, 0 x2567,
0 x2568, 0 x2564, 0 x2565, 0 x2559, 0 x2558, 0 x2552, 0 x2553, 0 x256b,
0 x256a, 0 x2518, 0 x250c, 0 x2588, 0 x2584, 0 x258c, 0 x2590, 0 x2580,
0 x03b1, 0 x00df, 0 x0393, 0 x03c0, 0 x03a3, 0 x03c3, 0 x00b5, 0 x03c4,
0 x03a6, 0 x0398, 0 x03a9, 0 x03b4, 0 x221e, 0 x03c6, 0 x03b5, 0 x2229,
0 x2261, 0 x00b1, 0 x2265, 0 x2264, 0 x2320, 0 x2321, 0 x00f7, 0 x2248,
0 x00b0, 0 x2219, 0 x00b7, 0 x221a, 0 x207f, 0 x00b2, 0 x25a0, 0 x00a0
},
/* User mapping -- default to codes for direct font mapping */
[USER_MAP] = {
0 xf000, 0 xf001, 0 xf002, 0 xf003, 0 xf004, 0 xf005, 0 xf006, 0 xf007,
0 xf008, 0 xf009, 0 xf00a, 0 xf00b, 0 xf00c, 0 xf00d, 0 xf00e, 0 xf00f,
0 xf010, 0 xf011, 0 xf012, 0 xf013, 0 xf014, 0 xf015, 0 xf016, 0 xf017,
0 xf018, 0 xf019, 0 xf01a, 0 xf01b, 0 xf01c, 0 xf01d, 0 xf01e, 0 xf01f,
0 xf020, 0 xf021, 0 xf022, 0 xf023, 0 xf024, 0 xf025, 0 xf026, 0 xf027,
0 xf028, 0 xf029, 0 xf02a, 0 xf02b, 0 xf02c, 0 xf02d, 0 xf02e, 0 xf02f,
0 xf030, 0 xf031, 0 xf032, 0 xf033, 0 xf034, 0 xf035, 0 xf036, 0 xf037,
0 xf038, 0 xf039, 0 xf03a, 0 xf03b, 0 xf03c, 0 xf03d, 0 xf03e, 0 xf03f,
0 xf040, 0 xf041, 0 xf042, 0 xf043, 0 xf044, 0 xf045, 0 xf046, 0 xf047,
0 xf048, 0 xf049, 0 xf04a, 0 xf04b, 0 xf04c, 0 xf04d, 0 xf04e, 0 xf04f,
0 xf050, 0 xf051, 0 xf052, 0 xf053, 0 xf054, 0 xf055, 0 xf056, 0 xf057,
0 xf058, 0 xf059, 0 xf05a, 0 xf05b, 0 xf05c, 0 xf05d, 0 xf05e, 0 xf05f,
0 xf060, 0 xf061, 0 xf062, 0 xf063, 0 xf064, 0 xf065, 0 xf066, 0 xf067,
0 xf068, 0 xf069, 0 xf06a, 0 xf06b, 0 xf06c, 0 xf06d, 0 xf06e, 0 xf06f,
0 xf070, 0 xf071, 0 xf072, 0 xf073, 0 xf074, 0 xf075, 0 xf076, 0 xf077,
0 xf078, 0 xf079, 0 xf07a, 0 xf07b, 0 xf07c, 0 xf07d, 0 xf07e, 0 xf07f,
0 xf080, 0 xf081, 0 xf082, 0 xf083, 0 xf084, 0 xf085, 0 xf086, 0 xf087,
0 xf088, 0 xf089, 0 xf08a, 0 xf08b, 0 xf08c, 0 xf08d, 0 xf08e, 0 xf08f,
0 xf090, 0 xf091, 0 xf092, 0 xf093, 0 xf094, 0 xf095, 0 xf096, 0 xf097,
0 xf098, 0 xf099, 0 xf09a, 0 xf09b, 0 xf09c, 0 xf09d, 0 xf09e, 0 xf09f,
0 xf0a0, 0 xf0a1, 0 xf0a2, 0 xf0a3, 0 xf0a4, 0 xf0a5, 0 xf0a6, 0 xf0a7,
0 xf0a8, 0 xf0a9, 0 xf0aa, 0 xf0ab, 0 xf0ac, 0 xf0ad, 0 xf0ae, 0 xf0af,
0 xf0b0, 0 xf0b1, 0 xf0b2, 0 xf0b3, 0 xf0b4, 0 xf0b5, 0 xf0b6, 0 xf0b7,
0 xf0b8, 0 xf0b9, 0 xf0ba, 0 xf0bb, 0 xf0bc, 0 xf0bd, 0 xf0be, 0 xf0bf,
0 xf0c0, 0 xf0c1, 0 xf0c2, 0 xf0c3, 0 xf0c4, 0 xf0c5, 0 xf0c6, 0 xf0c7,
0 xf0c8, 0 xf0c9, 0 xf0ca, 0 xf0cb, 0 xf0cc, 0 xf0cd, 0 xf0ce, 0 xf0cf,
0 xf0d0, 0 xf0d1, 0 xf0d2, 0 xf0d3, 0 xf0d4, 0 xf0d5, 0 xf0d6, 0 xf0d7,
0 xf0d8, 0 xf0d9, 0 xf0da, 0 xf0db, 0 xf0dc, 0 xf0dd, 0 xf0de, 0 xf0df,
0 xf0e0, 0 xf0e1, 0 xf0e2, 0 xf0e3, 0 xf0e4, 0 xf0e5, 0 xf0e6, 0 xf0e7,
0 xf0e8, 0 xf0e9, 0 xf0ea, 0 xf0eb, 0 xf0ec, 0 xf0ed, 0 xf0ee, 0 xf0ef,
0 xf0f0, 0 xf0f1, 0 xf0f2, 0 xf0f3, 0 xf0f4, 0 xf0f5, 0 xf0f6, 0 xf0f7,
0 xf0f8, 0 xf0f9, 0 xf0fa, 0 xf0fb, 0 xf0fc, 0 xf0fd, 0 xf0fe, 0 xf0ff
}
};
/* The standard kernel character-to-font mappings are not invertible
-- this is just a best effort. */
#define MAX_GLYPH 512 /* Max possible glyph value */
static enum translation_map inv_translate[MAX_NR_CONSOLES];
#define UNI_DIRS 32 U
#define UNI_DIR_ROWS 32 U
#define UNI_ROW_GLYPHS 64 U
#define UNI_DIR_BITS GENMASK(15 , 11 )
#define UNI_ROW_BITS GENMASK(10 , 6 )
#define UNI_GLYPH_BITS GENMASK( 5 , 0 )
#define UNI_DIR(uni) FIELD_GET(UNI_DIR_BITS, (uni))
#define UNI_ROW(uni) FIELD_GET(UNI_ROW_BITS, (uni))
#define UNI_GLYPH(uni) FIELD_GET(UNI_GLYPH_BITS, (uni))
#define UNI(dir, row, glyph) (FIELD_PREP(UNI_DIR_BITS, (dir)) | \
FIELD_PREP(UNI_ROW_BITS, (row)) | \
FIELD_PREP(UNI_GLYPH_BITS, (glyph)))
/**
* struct uni_pagedict - unicode directory
*
* @ uni_pgdir : 32 * 32 * 64 table with glyphs
* @ refcount : reference count of this structure
* @ sum : checksum
* @ inverse_translations : best - effort inverse mapping
* @ inverse_trans_unicode : best - effort inverse mapping to unicode
*/
struct uni_pagedict {
u16 **uni_pgdir[UNI_DIRS];
unsigned long refcount;
unsigned long sum;
unsigned char *inverse_translations[LAST_MAP + 1 ];
u16 *inverse_trans_unicode;
};
static struct uni_pagedict *dflt;
static void set_inverse_transl(struct vc_data *conp, struct uni_pagedict *dict,
enum translation_map m)
{
unsigned short *t = translations[m];
unsigned char *inv;
if (!dict)
return ;
inv = dict->inverse_translations[m];
if (!inv) {
inv = dict->inverse_translations[m] = kmalloc(MAX_GLYPH,
GFP_KERNEL);
if (!inv)
return ;
}
memset(inv, 0 , MAX_GLYPH);
for (unsigned int ch = 0 ; ch < ARRAY_SIZE(translations[m]); ch++) {
int glyph = conv_uni_to_pc(conp, t[ch]);
if (glyph >= 0 && glyph < MAX_GLYPH && inv[glyph] < 32 ) {
/* prefer '-' above SHY etc. */
inv[glyph] = ch;
}
}
}
static void set_inverse_trans_unicode(struct uni_pagedict *dict)
{
unsigned int d, r, g;
u16 *inv;
if (!dict)
return ;
inv = dict->inverse_trans_unicode;
if (!inv) {
inv = dict->inverse_trans_unicode = kmalloc_array(MAX_GLYPH,
sizeof (*inv), GFP_KERNEL);
if (!inv)
return ;
}
memset(inv, 0 , MAX_GLYPH * sizeof (*inv));
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);
}
}
}
}
unsigned short *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(const struct 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;
return p->inverse_translations[m][glyph];
}
EXPORT_SYMBOL_GPL(inverse_translate);
static void update_user_maps(void )
{
int i;
struct uni_pagedict *p, *q = NULL;
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
* 0 xf000 - 0 xf0ff " transparent " Unicodes ) whereas the " new " variants set
* Unicodes explicitly .
*/
int con_set_trans_old(unsigned char __user * arg)
{
unsigned short inbuf[E_TABSZ];
unsigned int i;
unsigned char ch;
for (i = 0 ; i < ARRAY_SIZE(inbuf); i++) {
if (get_user(ch, &arg[i]))
return -EFAULT;
inbuf[i] = UNI_DIRECT_BASE | ch;
}
console_lock();
memcpy(translations[USER_MAP], inbuf, sizeof (inbuf));
update_user_maps();
console_unlock();
return 0 ;
}
int con_get_trans_old(unsigned char __user * arg)
{
int i, ch;
unsigned short *p = translations[USER_MAP];
unsigned char outbuf[E_TABSZ];
console_lock();
for (i = 0 ; i < ARRAY_SIZE(outbuf); i++)
{
ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
outbuf[i] = (ch & ~0 xff) ? 0 : ch;
}
console_unlock();
return copy_to_user(arg, outbuf, sizeof (outbuf)) ? -EFAULT : 0 ;
}
int con_set_trans_new(ushort __user * arg)
{
unsigned short inbuf[E_TABSZ];
if (copy_from_user(inbuf, arg, sizeof (inbuf)))
return -EFAULT;
console_lock();
memcpy(translations[USER_MAP], inbuf, sizeof (inbuf));
update_user_maps();
console_unlock();
return 0 ;
}
int con_get_trans_new(ushort __user * arg)
{
unsigned short outbuf[E_TABSZ];
console_lock();
memcpy(outbuf, translations[USER_MAP], sizeof (outbuf));
console_unlock();
return copy_to_user(arg, outbuf, sizeof (outbuf)) ? -EFAULT : 0 ;
}
/*
* 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[];
static void con_release_unimap(struct uni_pagedict *dict)
{
unsigned int d, r;
if (dict == dflt)
dflt = NULL;
for (d = 0 ; d < UNI_DIRS; d++) {
u16 **dir = dict->uni_pgdir[d];
if (dir != NULL) {
for (r = 0 ; r < UNI_DIR_ROWS; r++)
kfree(dir[r]);
kfree(dir);
}
dict->uni_pgdir[d] = NULL;
}
for (r = 0 ; r < ARRAY_SIZE(dict->inverse_translations); r++) {
kfree(dict->inverse_translations[r]);
dict->inverse_translations[r] = NULL;
}
kfree(dict->inverse_trans_unicode);
dict->inverse_trans_unicode = NULL;
}
/* Caller must hold the console lock */
void con_free_unimap(struct vc_data *vc)
{
struct uni_pagedict *p;
p = *vc->uni_pagedict_loc;
if (!p)
return ;
*vc->uni_pagedict_loc = NULL;
if (--p->refcount)
return ;
con_release_unimap(p);
kfree(p);
}
static int con_unify_unimap(struct vc_data *conp, struct uni_pagedict *dict1)
{
struct uni_pagedict *dict2;
unsigned int cons, d, r;
for (cons = 0 ; cons < MAX_NR_CONSOLES; cons++) {
if (!vc_cons_allocated(cons))
continue ;
dict2 = *vc_cons[cons].d->uni_pagedict_loc;
if (!dict2 || dict2 == dict1 || dict2->sum != dict1->sum)
continue ;
for (d = 0 ; d < UNI_DIRS; d++) {
u16 **dir1 = dict1->uni_pgdir[d];
u16 **dir2 = dict2->uni_pgdir[d];
if (!dir1 && !dir2)
continue ;
if (!dir1 || !dir2)
break ;
for (r = 0 ; r < UNI_DIR_ROWS; r++) {
if (!dir1[r] && !dir2[r])
continue ;
if (!dir1[r] || !dir2[r])
break ;
if (memcmp(dir1[r], dir2[r], UNI_ROW_GLYPHS *
sizeof (*dir1[r])))
break ;
}
if (r < UNI_DIR_ROWS)
break ;
}
if (d == UNI_DIRS) {
dict2->refcount++;
*conp->uni_pagedict_loc = dict2;
con_release_unimap(dict1);
kfree(dict1);
return 1 ;
}
}
return 0 ;
}
static int
con_insert_unipair(struct uni_pagedict *p, u_short unicode, u_short fontpos)
{
u16 **dir, *row;
unsigned int n;
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, 0 xff, UNI_ROW_GLYPHS * sizeof (*row));
}
row[UNI_GLYPH(unicode)] = fontpos;
p->sum += (fontpos << 20 U) + unicode;
return 0 ;
}
static int con_allocate_new(struct vc_data *vc)
{
struct uni_pagedict *new , *old = *vc->uni_pagedict_loc;
new = kzalloc(sizeof (*new ), GFP_KERNEL);
if (!new )
return -ENOMEM;
new ->refcount = 1 ;
*vc->uni_pagedict_loc = new ;
if (old)
old->refcount--;
return 0 ;
}
/* Caller must hold the lock */
static int con_do_clear_unimap(struct vc_data *vc)
{
struct uni_pagedict *old = *vc->uni_pagedict_loc;
if (!old || old->refcount > 1 )
return con_allocate_new(vc);
old->sum = 0 ;
con_release_unimap(old);
return 0 ;
}
int con_clear_unimap(struct vc_data *vc)
{
int ret;
console_lock();
ret = con_do_clear_unimap(vc);
console_unlock();
return ret;
}
static struct uni_pagedict *con_unshare_unimap(struct vc_data *vc,
struct uni_pagedict *old)
{
struct uni_pagedict *new ;
unsigned int d, r, g;
int ret;
u16 uni = 0 ;
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] == 0 xffff)
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);
}
}
}
}
return new ;
}
int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
{
int err = 0 , err1;
struct uni_pagedict *dict;
struct unipair *unilist, *plist;
if (!ct)
return 0 ;
unilist = vmemdup_array_user(list, ct, sizeof (*unilist));
if (IS_ERR(unilist))
return PTR_ERR(unilist);
console_lock();
/* Save original vc_unipagdir_loc in case we allocate a new one */
dict = *vc->uni_pagedict_loc;
if (!dict) {
err = -EINVAL;
goto out_unlock;
}
if (dict->refcount > 1 ) {
dict = con_unshare_unimap(vc, dict);
if (IS_ERR(dict)) {
err = PTR_ERR(dict);
goto out_unlock;
}
} else if (dict == dflt) {
dflt = NULL;
}
/*
* Insert user specified unicode pairs into new table .
*/
for (plist = unilist; ct; ct--, plist++) {
err1 = con_insert_unipair(dict, plist->unicode, plist->fontpos);
if (err1)
err = err1;
}
/*
* Merge with fontmaps of any other virtual consoles .
*/
if (con_unify_unimap(vc, dict))
goto out_unlock;
for (enum translation_map m = FIRST_MAP; m <= LAST_MAP; m++)
set_inverse_transl(vc, dict, m);
set_inverse_trans_unicode(dict);
out_unlock:
console_unlock();
kvfree(unilist);
return err;
}
/**
* 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;
unsigned int fontpos, count;
int err = 0 , err1;
u16 *dfont;
if (dflt) {
dict = *vc->uni_pagedict_loc;
if (dict == dflt)
return 0 ;
dflt->refcount++;
*vc->uni_pagedict_loc = dflt;
if (dict && !--dict->refcount) {
con_release_unimap(dict);
kfree(dict);
}
return 0 ;
}
/* The default font is always 256 characters */
err = con_do_clear_unimap(vc);
if (err)
return err;
dict = *vc->uni_pagedict_loc;
dfont = dfont_unitable;
for (fontpos = 0 ; fontpos < 256 U; 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;
if (!*src_vc->uni_pagedict_loc)
return -EINVAL;
if (*dst_vc->uni_pagedict_loc == *src_vc->uni_pagedict_loc)
return 0 ;
con_free_unimap(dst_vc);
src = *src_vc->uni_pagedict_loc;
src->refcount++;
*dst_vc->uni_pagedict_loc = src;
return 0 ;
}
EXPORT_SYMBOL(con_copy_unimap);
/*
* 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;
unsigned int 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(unsigned char c)
{
unsigned short uni = translations[USER_MAP][c];
return uni == (0 xf000 | 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 | 0 xf000) && 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 > 0 xffff)
return -4 ; /* Not found */
else if (ucs < 0 x20)
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 .
*/
else if ((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 in Prozent C=92 H=94 G=92
¤ Dauer der Verarbeitung: 0.16 Sekunden
(vorverarbeitet am 2026-10-11)
¤
*© Formatika GbR, Deutschland