From: Alan Mackenzie <acm@muc.de>
To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
Jiri Slaby <jirislaby@kernel.org>,
Simona Vetter <simona@ffwll.ch>,
linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org,
Helge Deller <deller@gmx.de>,
Thomas Zimmermann <tzimmermann@suse.de>,
linux-fbdev@vger.kernel.org, dri-devel@lists.freedesktop.org
Cc: acm@muc.de
Subject: [Patch 8/9]: vt: Enhancements to the VT ioctl interface
Date: Thu, 27 Aug 2026 18:56:30 +0000 [thread overview]
Message-ID: <apCIXtwoPY_a3QOi@MAC.fritz.box> (raw)
In-Reply-To: <apCEDM2sWv_M354-@MAC.fritz.box>
vt: 32b glyph: 10. Enhancements to the VT ioctl interface
Handle the current 16-bit P/GIO_UNIMAP ioctls by converting
to/from 32-bit code-points/glyph numbers. Add handling for new
32-bit ioctls P/GIO_UNIMAP21. Convert to and from __user in
vt_ioctl.c rather than in vt.c or consolemap.c.
Signed-off-by: Alan Mackenzie <acm@muc.de>
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
index 28993a3d0acb..05986430e1bb 100644
--- a/drivers/tty/vt/vt_ioctl.c
+++ b/drivers/tty/vt/vt_ioctl.c
@@ -24,7 +24,6 @@
#include <linux/major.h>
#include <linux/fs.h>
#include <linux/console.h>
-#include <linux/consolemap.h>
#include <linux/signal.h>
#include <linux/suspend.h>
#include <linux/timex.h>
@@ -36,6 +35,7 @@
#include <linux/kbd_kern.h>
#include <linux/vt_kern.h>
+#include <linux/consolemap.h>
#include <linux/kbd_diacr.h>
#include <linux/selection.h>
@@ -484,10 +484,155 @@ static int vt_k_ioctl(struct tty_struct *tty, unsigned int cmd,
return 0;
}
+#ifdef CONFIG_FB_GLYPH_21BIT
+static int vt__user_unipair_8_to_21(unsigned int ct,
+ struct unipair __user *entries,
+ struct unipair21 **tmp21_entries)
+{
+ struct unipair *tmp_entries;
+ int i, ret = 0;
+
+ tmp_entries = kmalloc_array(ct, sizeof(struct unipair), GFP_KERNEL);
+ if (!tmp_entries)
+ return -ENOMEM;
+ if (copy_from_user(tmp_entries, entries, ct * sizeof(struct unipair))) {
+ ret = -EFAULT;
+ goto free_tmp;
+ }
+ *tmp21_entries = kmalloc_array(ct, sizeof(struct unipair21), GFP_KERNEL);
+ if (!*tmp21_entries) {
+ ret = -ENOMEM;
+ goto free_tmp;
+ }
+ for (i = 0; i < ct; i++) {
+ (*tmp21_entries)[i].unicode = tmp_entries[i].unicode;
+ (*tmp21_entries)[i].fontpos = tmp_entries[i].fontpos;
+ }
+free_tmp: kfree(tmp_entries);
+ return ret;
+}
+
+static int vt_unipair_21_to__user_8(unsigned int ct,
+ struct unipair21 *entries21,
+ struct unipair __user *entries)
+{
+ struct unipair *tmp_entries;
+ int i, ret = 0;
+
+ tmp_entries = kmalloc_array(ct, sizeof(struct unipair), GFP_KERNEL);
+ if (!tmp_entries)
+ return -ENOMEM;
+ for (i = 0; i < ct; i++) {
+ if ((entries21[i].unicode > 0xffff) ||
+ (entries21[i].fontpos > 0xffff)) {
+ ret = -EINVAL;
+ goto free_tmp;
+ }
+ tmp_entries[i].unicode = entries21[i].unicode;
+ tmp_entries[i].fontpos = entries21[i].fontpos;
+ }
+ if (copy_to_user(entries, tmp_entries, ct * sizeof(struct unipair)))
+ ret = -EFAULT;
+free_tmp: kfree(tmp_entries);
+ return ret;
+}
+
static inline int do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud,
bool perm, struct vc_data *vc)
{
struct unimapdesc tmp;
+ struct unipair21 *tmp21_entries = NULL;
+ int ret = 0, ret1 = 0;
+ unsigned int ct;
+
+ if (copy_from_user(&tmp, user_ud, sizeof(tmp)))
+ return -EFAULT;
+ switch (cmd) {
+ case PIO_UNIMAP:
+ if (!perm)
+ return -EPERM;
+ ret = vt__user_unipair_8_to_21(tmp.entry_ct, tmp.entries,
+ &tmp21_entries);
+ if (ret)
+ return ret;
+ ret = con_set_unimap(vc, tmp.entry_ct, tmp21_entries);
+ kfree(tmp21_entries);
+ return ret;
+
+ case GIO_UNIMAP:
+ if (!perm && fg_console != vc->vc_num)
+ return -EPERM;
+ tmp21_entries = kmalloc_array(tmp.entry_ct,
+ sizeof(struct unipair21),
+ GFP_KERNEL);
+ if (!tmp21_entries)
+ return -ENOMEM;
+ ret = con_get_unimap(vc, tmp.entry_ct, &ct, tmp21_entries);
+ if (ret)
+ goto free_tmp21;
+ ret = vt_unipair_21_to__user_8(ct, tmp21_entries, tmp.entries);
+free_tmp21: ret1 = put_user(ct, &user_ud->entry_ct);
+ kfree(tmp21_entries);
+ return ret ? ret : ret1;
+ }
+ return 0;
+}
+
+static inline int do_unimap_ioctl21(int cmd, struct unimapdesc21 __user *user_ud,
+ bool perm, struct vc_data *vc)
+{
+ struct unimapdesc21 tmp;
+ struct unipair21 *k_entries;
+ int ret = 0, ret1 = 0;
+
+ if (copy_from_user(&tmp, user_ud, sizeof(tmp)))
+ return -EFAULT;
+ switch (cmd) {
+ case PIO_UNIMAP21:
+ if (!perm)
+ return -EPERM;
+ k_entries = kmalloc_array(tmp.entry_ct,
+ sizeof(struct unipair21),
+ GFP_KERNEL);
+ if (!k_entries)
+ return -ENOMEM;
+ if (copy_from_user(k_entries, tmp.entries,
+ tmp.entry_ct * sizeof(struct unipair21))) {
+ ret = -EFAULT;
+ goto free_k_entries;
+ }
+ ret = con_set_unimap(vc, tmp.entry_ct, k_entries);
+free_k_entries: kfree(k_entries);
+ return ret;
+ case GIO_UNIMAP21:
+ if (!perm && fg_console != vc->vc_num)
+ return -EPERM;
+ k_entries = kmalloc_array(tmp.entry_ct,
+ sizeof(struct unipair21),
+ GFP_KERNEL);
+ if (!k_entries)
+ return -ENOMEM;
+ ret = con_get_unimap(vc, tmp.entry_ct, &tmp.entry_ct,
+ k_entries);
+ if (ret)
+ goto free_k_entries1;
+ if (copy_to_user(tmp.entries, k_entries,
+ tmp.entry_ct * sizeof(struct unipair21)))
+ ret = -EFAULT;
+free_k_entries1: ret1 = put_user(tmp.entry_ct, &user_ud->entry_ct);
+ kfree(k_entries);
+ return ret ? ret : ret1;
+ }
+ return 0;
+}
+
+#else
+static inline int do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud,
+ bool perm, struct vc_data *vc)
+{
+ struct unimapdesc tmp;
+ struct unipair *k_entries;
+ int ret = 0, ret1 = 0;
if (copy_from_user(&tmp, user_ud, sizeof tmp))
return -EFAULT;
@@ -495,15 +640,41 @@ static inline int do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud,
case PIO_UNIMAP:
if (!perm)
return -EPERM;
- return con_set_unimap(vc, tmp.entry_ct, tmp.entries);
+ k_entries = kmalloc_array(tmp.entry_ct,
+ sizeof(struct unipair),
+ GFP_KERNEL);
+ if (!k_entries)
+ return -ENOMEM;
+ if (copy_from_user(k_entries, tmp.entries,
+ tmp.entry_ct * sizeof(struct unipair))) {
+ ret = -EFAULT;
+ goto free_k_entries;
+ }
+ ret = con_set_unimap(vc, tmp.entry_ct, k_entries);
+free_k_entries: kfree(k_entries);
+ return ret;
case GIO_UNIMAP:
if (!perm && fg_console != vc->vc_num)
return -EPERM;
- return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct),
- tmp.entries);
+ k_entries = kmalloc_array(tmp.entry_ct,
+ sizeof(struct unipair),
+ GFP_KERNEL);
+ if (!k_entries)
+ return -ENOMEM;
+ ret = con_get_unimap(vc, tmp.entry_ct, &tmp.entry_ct,
+ k_entries);
+ if (ret)
+ goto free_k_entries1;
+ if (copy_to_user(tmp.entries, k_entries,
+ tmp.entry_ct * sizeof(struct unipair)))
+ ret = -EFAULT;
+free_k_entries1: ret1 = put_user(tmp.entry_ct, &user_ud->entry_ct);
+ kfree(k_entries);
+ return ret ? ret : ret1;
}
return 0;
}
+#endif /* CONFIG_FB_GLYPH_21BIT */
static int vt_io_ioctl(struct vc_data *vc, unsigned int cmd, void __user *up,
bool perm)
@@ -543,6 +714,12 @@ static int vt_io_ioctl(struct vc_data *vc, unsigned int cmd, void __user *up,
case GIO_UNIMAP:
return do_unimap_ioctl(cmd, up, perm, vc);
+#ifdef CONFIG_FB_GLYPH_21BIT
+ case PIO_UNIMAP21:
+ case GIO_UNIMAP21:
+ return do_unimap_ioctl21(cmd, up, perm, vc);
+#endif
+
default:
return -ENOIOCTLCMD;
}
@@ -1026,16 +1203,20 @@ compat_kdfontop_ioctl(struct compat_console_font_op __user *fontop,
}
struct compat_unimapdesc {
- unsigned short entry_ct;
+ u16 entry_ct;
compat_caddr_t entries;
};
+#ifdef CONFIG_FB_GLYPH_21BIT
static inline int
compat_unimap_ioctl(unsigned int cmd, struct compat_unimapdesc __user *user_ud,
int perm, struct vc_data *vc)
{
struct compat_unimapdesc tmp;
struct unipair __user *tmp_entries;
+ struct unipair21 *tmp21_entries = NULL;
+ int ret = 0, ret1 = 0;
+ unsigned int ct;
if (copy_from_user(&tmp, user_ud, sizeof tmp))
return -EFAULT;
@@ -1044,14 +1225,83 @@ compat_unimap_ioctl(unsigned int cmd, struct compat_unimapdesc __user *user_ud,
case PIO_UNIMAP:
if (!perm)
return -EPERM;
- return con_set_unimap(vc, tmp.entry_ct, tmp_entries);
+ ret = vt__user_unipair_8_to_21(tmp.entry_ct, tmp_entries,
+ &tmp21_entries);
+ if (ret)
+ return ret;
+ ret = con_set_unimap(vc, tmp.entry_ct, tmp21_entries);
+ kfree(tmp21_entries);
+ return ret;
+
case GIO_UNIMAP:
if (!perm && fg_console != vc->vc_num)
return -EPERM;
- return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp_entries);
+ tmp21_entries = kmalloc_array(tmp.entry_ct,
+ sizeof(struct unipair21),
+ GFP_KERNEL);
+ if (!tmp21_entries)
+ return -ENOMEM;
+ ret = con_get_unimap(vc, tmp.entry_ct, &ct, tmp21_entries);
+ if (ret)
+ goto free_tmp21;
+ ret = vt_unipair_21_to__user_8(ct, tmp21_entries, tmp_entries);
+free_tmp21: ret1 = put_user(ct, &user_ud->entry_ct);
+ kfree(tmp21_entries);
+ return ret ? ret : ret1;
+ }
+ return 0;
+}
+#else
+static inline int
+compat_unimap_ioctl(unsigned int cmd, struct compat_unimapdesc __user *user_ud,
+ int perm, struct vc_data *vc)
+{
+ struct compat_unimapdesc tmp;
+ struct unipair __user *tmp_entries;
+ struct unipair *k_entries;
+ int ret = 0, ret1 = 0;
+
+ if (copy_from_user(&tmp, user_ud, sizeof(tmp)))
+ return -EFAULT;
+ tmp_entries = compat_ptr(tmp.entries);
+ switch (cmd) {
+ case PIO_UNIMAP:
+ if (!perm)
+ return -EPERM;
+ k_entries = kmalloc_array(tmp.entry_ct,
+ sizeof(struct unipair),
+ GFP_KERNEL);
+ if (!k_entries)
+ return -ENOMEM;
+ if (copy_from_user(k_entries, tmp_entries,
+ tmp.entry_ct * sizeof(struct unipair))) {
+ ret = -EFAULT;
+ goto free_k_entries;
+ }
+ ret = con_set_unimap(vc, tmp.entry_ct, k_entries);
+free_k_entries: kfree(k_entries);
+ return ret;
+ case GIO_UNIMAP:
+ if (!perm && fg_console != vc->vc_num)
+ return -EPERM;
+ k_entries = kmalloc_array(tmp.entry_ct, sizeof(struct unipair),
+ GFP_KERNEL);
+ if (!k_entries)
+ return -ENOMEM;
+ ret = con_get_unimap(vc, tmp.entry_ct, &tmp.entry_ct,
+ k_entries);
+ if (ret)
+ goto free_k_entries1;
+ if (copy_to_user(tmp_entries, k_entries,
+ tmp.entry_ct * sizeof(struct unipair)))
+ ret = -EFAULT;
+free_k_entries1: ret1 = put_user(tmp.entry_ct, &user_ud->entry_ct);
+ kfree(k_entries);
+ return ret ? ret : ret1;
}
return 0;
}
+#endif /* CONFIG_FB_GLYPH_21BIT */
long vt_compat_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
diff --git a/include/uapi/linux/kd.h b/include/uapi/linux/kd.h
index 6b384065c013..342654dfbc16 100644
--- a/include/uapi/linux/kd.h
+++ b/include/uapi/linux/kd.h
@@ -56,7 +56,7 @@ typedef char scrnmap_t;
#define GIO_SCRNMAP 0x4B40 /* get screen mapping from kernel */
#define PIO_SCRNMAP 0x4B41 /* put screen mapping table in kernel */
#define GIO_UNISCRNMAP 0x4B69 /* get full Unicode screen mapping */
-#define PIO_UNISCRNMAP 0x4B6A /* set full Unicode screen mapping */
+#define PIO_UNISCRNMAP 0x4B6A /* set full Unicode screen mapping */
#define GIO_UNIMAP 0x4B66 /* get unicode-to-font mapping from kernel */
struct unipair {
@@ -67,8 +67,19 @@ struct unimapdesc {
unsigned short entry_ct;
struct unipair __user *entries;
};
+struct unipair21 {
+ unsigned int unicode;
+ unsigned int fontpos;
+};
+struct unimapdesc21 {
+ unsigned int entry_ct;
+ struct unipair21 __user *entries;
+};
#define PIO_UNIMAP 0x4B67 /* put unicode-to-font mapping in kernel */
#define PIO_UNIMAPCLR 0x4B68 /* clear table, possibly advise hash algorithm */
+#define GIO_UNIMAP21 0x4B6E /* get 21-bit unicode-to-font mapping from kernel */
+#define PIO_UNIMAP21 0x4B6F /* put 21-bit unicode-to-font mapping to kernel */
+
struct unimapinit {
unsigned short advised_hashsize; /* 0 if no opinion */
unsigned short advised_hashstep; /* 0 if no opinion */
@@ -185,6 +196,6 @@ struct console_font {
/* note: 0x4B00-0x4B4E all have had a value at some time;
don't reuse for the time being */
-/* note: 0x4B60-0x4B6D, 0x4B70-0x4B72 used above */
+/* note: 0x4B60-0x4B6F, 0x4B70-0x4B72 used above */
#endif /* _UAPI_LINUX_KD_H */
diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h
index d008c3d0a9bb..af99aeefe177 100644
--- a/include/linux/vt_kern.h
+++ b/include/linux/vt_kern.h
@@ -90,13 +96,13 @@ static inline int con_clear_unimap(struct vc_data *vc)
return 0;
}
static inline
-int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
+int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair *list)
{
return 0;
}
static inline
-int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct,
- struct unipair __user *list)
+int con_get_unimap(struct vc_data *vc, ushort ct, ushort *uct,
+ struct unipair *list)
{
return -EINVAL;
}
--
Alan Mackenzie (Nuremberg, Germany).
next prev parent reply other threads:[~2026-08-27 18:56 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-27 18:38 vt: Enlarge the framebuffer glyph size from 16 to 32 bits Alan Mackenzie
2026-08-27 18:42 ` [Patch 1/9]: Make consolemap.c handle Unicode planes outside BMP Alan Mackenzie
2026-08-27 19:14 ` sashiko-bot
2026-08-28 4:57 ` Jiri Slaby
2026-08-29 11:51 ` Alan Mackenzie
2026-08-27 18:45 ` [Patch 2/9]: Glyph size: Use GLYPH_SZ/HW rather than hardcoded 2, 1 Alan Mackenzie
2026-08-27 19:22 ` sashiko-bot
2026-08-27 18:47 ` [Patch 3/9]: Replace scr_readw/writew by scr_readg/writeg, etc Alan Mackenzie
2026-08-27 19:18 ` sashiko-bot
2026-08-29 12:11 ` Greg Kroah-Hartman
2026-08-29 13:33 ` Alan Mackenzie
2026-08-27 18:48 ` [Patch 4/9]: Amend internal manipulation of glyph structure Alan Mackenzie
2026-08-27 19:19 ` sashiko-bot
2026-08-27 18:50 ` [Patch 5/9]: vt: Amend three Kconfig files Alan Mackenzie
2026-08-27 19:12 ` sashiko-bot
2026-08-27 18:52 ` [Patch 6/9]: vt: Use u32 and typedef u1632 to handle whole glyphs Alan Mackenzie
2026-08-27 19:22 ` sashiko-bot
2026-08-27 18:54 ` [Patch 7/9]: vt: Handle up to 2^21 glyphs, rather than 256/512 Alan Mackenzie
2026-08-27 19:14 ` sashiko-bot
2026-08-27 18:56 ` Alan Mackenzie [this message]
2026-08-27 19:25 ` [Patch 8/9]: vt: Enhancements to the VT ioctl interface sashiko-bot
2026-08-27 18:58 ` [Patch 9/9]: vt: Misc changes, e.g. to #include directives Alan Mackenzie
2026-08-27 19:25 ` sashiko-bot
2026-08-29 12:06 ` Greg Kroah-Hartman
2026-08-28 6:12 ` vt: Enlarge the framebuffer glyph size from 16 to 32 bits Thomas Zimmermann
2026-08-28 14:36 ` Alan Mackenzie
2026-08-29 12:09 ` Greg Kroah-Hartman
2026-08-29 14:39 ` Alan Mackenzie
2026-08-31 6:20 ` Thomas Zimmermann
2026-08-31 14:45 ` Alan Mackenzie
2026-08-31 17:21 ` Helge Deller
2026-09-01 11:14 ` Alan Mackenzie
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=apCIXtwoPY_a3QOi@MAC.fritz.box \
--to=acm@muc.de \
--cc=deller@gmx.de \
--cc=dri-devel@lists.freedesktop.org \
--cc=gregkh@linuxfoundation.org \
--cc=jirislaby@kernel.org \
--cc=linux-fbdev@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-serial@vger.kernel.org \
--cc=simona@ffwll.ch \
--cc=tzimmermann@suse.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.