summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS2
-rw-r--r--configure.ac1
-rw-r--r--src/Makefile.am2
-rw-r--r--src/defs.h1
-rw-r--r--src/ioctl.c2
-rw-r--r--src/kd_ioctl.c817
-rw-r--r--src/kd_mpers_ioctl.c269
-rw-r--r--src/xlat/kd_default_led_flags.in7
-rw-r--r--src/xlat/kd_font_flags.in2
-rw-r--r--src/xlat/kd_font_ops.in5
-rw-r--r--src/xlat/kd_ioctl_cmds.in48
-rw-r--r--src/xlat/kd_kbd_modes.in6
-rw-r--r--src/xlat/kd_kbd_types.in3
-rw-r--r--src/xlat/kd_key_ascii_keys.in27
-rw-r--r--src/xlat/kd_key_brl_keys.in12
-rw-r--r--src/xlat/kd_key_cur_keys.in5
-rw-r--r--src/xlat/kd_key_dead_keys.in28
-rw-r--r--src/xlat/kd_key_fn_key_vals.in258
-rw-r--r--src/xlat/kd_key_fn_keys.in257
-rw-r--r--src/xlat/kd_key_lock_keys.in10
-rw-r--r--src/xlat/kd_key_pad_keys.in21
-rw-r--r--src/xlat/kd_key_shift_keys.in10
-rw-r--r--src/xlat/kd_key_slock_keys.in10
-rw-r--r--src/xlat/kd_key_spec_keys.in23
-rw-r--r--src/xlat/kd_key_tables.in5
-rw-r--r--src/xlat/kd_key_types.in16
-rw-r--r--src/xlat/kd_keymap_flags.in8
-rw-r--r--src/xlat/kd_led_flags.in3
-rw-r--r--src/xlat/kd_meta_vals.in2
-rw-r--r--src/xlat/kd_modes.in5
-rw-r--r--tests/.gitignore12
-rw-r--r--tests/Makefile.am8
-rw-r--r--tests/gen_tests.in12
-rw-r--r--tests/ioctl_kd-Xabbrev.c1
-rw-r--r--tests/ioctl_kd-Xraw.c2
-rw-r--r--tests/ioctl_kd-Xverbose.c2
-rw-r--r--tests/ioctl_kd-success-Xabbrev.c1
-rw-r--r--tests/ioctl_kd-success-Xraw.c2
-rw-r--r--tests/ioctl_kd-success-Xverbose.c2
-rw-r--r--tests/ioctl_kd-success-s1024-Xabbrev.c2
-rw-r--r--tests/ioctl_kd-success-s1024-Xraw.c2
-rw-r--r--tests/ioctl_kd-success-s1024-Xverbose.c2
-rw-r--r--tests/ioctl_kd-success-s1024.c2
-rw-r--r--tests/ioctl_kd-success.c2
-rw-r--r--tests/ioctl_kd.c1733
-rwxr-xr-xtests/pure_executables.list4
46 files changed, 3653 insertions, 1 deletions
diff --git a/NEWS b/NEWS
index 899b51d86..fa17c9d30 100644
--- a/NEWS
+++ b/NEWS
@@ -8,7 +8,7 @@ Noteworthy changes in release ?.?? (????-??-??)
* Implemented decoding of process_mrelease syscall, introduced in Linux 5.15.
* Implemented decoding of SECCOMP_GET_NOTIF_SIZES operation of seccomp
syscall.
- * Implemented decoding of SECCOMP_* ioctl commands.
+ * Implemented decoding of KD* and SECCOMP_* ioctl commands.
* Enhanced decoding of io_uring_register and times syscalls.
* Updated lists of BTRFS_*, DM_*, FAN_REPORT_*, IORING_* and MPOL_*
constants.
diff --git a/configure.ac b/configure.ac
index e662c12f4..058825907 100644
--- a/configure.ac
+++ b/configure.ac
@@ -424,6 +424,7 @@ AC_CHECK_HEADERS(m4_normalize([
elf.h
gcov.h
iconv.h
+ linux/kd.h
mqueue.h
netinet/sctp.h
netipx/ipx.h
diff --git a/src/Makefile.am b/src/Makefile.am
index e686c2f99..f11ef1254 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -160,6 +160,8 @@ libstrace_a_SOURCES = \
ipc_shm.c \
ipc_shmctl.c \
kcmp.c \
+ kd_ioctl.c \
+ kd_mpers_ioctl.c \
kernel_dirent.h \
kernel_fcntl.h \
kernel_rusage.h \
diff --git a/src/defs.h b/src/defs.h
index b634e4e67..feb8b6c13 100644
--- a/src/defs.h
+++ b/src/defs.h
@@ -1338,6 +1338,7 @@ DECL_IOCTL(fs_f);
DECL_IOCTL(fs_x);
DECL_IOCTL(gpio);
DECL_IOCTL(inotify);
+DECL_IOCTL(kd);
DECL_IOCTL(kvm);
DECL_IOCTL(nbd);
DECL_IOCTL(nsfs);
diff --git a/src/ioctl.c b/src/ioctl.c
index f32ae9761..1965af32c 100644
--- a/src/ioctl.c
+++ b/src/ioctl.c
@@ -366,6 +366,8 @@ ioctl_decode(struct tcb *tcp)
return evdev_ioctl(tcp, code, arg);
case 'I':
return inotify_ioctl(tcp, code, arg);
+ case 'K':
+ return kd_ioctl(tcp, code, arg);
case 'L':
return loop_ioctl(tcp, code, arg);
case 'M':
diff --git a/src/kd_ioctl.c b/src/kd_ioctl.c
new file mode 100644
index 000000000..3102cf5af
--- /dev/null
+++ b/src/kd_ioctl.c
@@ -0,0 +1,817 @@
+/*
+ * Support for decoding of VT ioctl commands.
+ *
+ * Copyright (c) 2019-2021 Eugene Syromyatnikov <evgsyr@gmail.com>
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "defs.h"
+
+#include <linux/kd.h>
+#include <linux/keyboard.h>
+
+#include "print_fields.h"
+#include "print_utils.h"
+
+#include "xlat/kd_default_led_flags.h"
+#include "xlat/kd_kbd_modes.h"
+#include "xlat/kd_kbd_types.h"
+#include "xlat/kd_keymap_flags.h"
+#include "xlat/kd_key_tables.h"
+#include "xlat/kd_key_types.h"
+#include "xlat/kd_key_fn_keys.h"
+#include "xlat/kd_key_fn_key_vals.h"
+#include "xlat/kd_key_spec_keys.h"
+#include "xlat/kd_key_pad_keys.h"
+#include "xlat/kd_key_dead_keys.h"
+#include "xlat/kd_key_cur_keys.h"
+#include "xlat/kd_key_shift_keys.h"
+#include "xlat/kd_key_ascii_keys.h"
+#include "xlat/kd_key_lock_keys.h"
+#include "xlat/kd_key_slock_keys.h"
+#include "xlat/kd_key_brl_keys.h"
+#include "xlat/kd_led_flags.h"
+#include "xlat/kd_meta_vals.h"
+#include "xlat/kd_modes.h"
+
+#define XLAT_MACROS_ONLY
+# include "xlat/kd_ioctl_cmds.h"
+#undef XLAT_MACROS_ONLY
+
+enum {
+ KERNEL_PIT_TICK_RATE = 1193182,
+ KERNEL_E_TABSZ = 256,
+ KERNEL_MAX_DIACR = 256,
+};
+
+static int
+kiocsound(struct tcb *const tcp, const kernel_ulong_t arg)
+{
+ unsigned int freq = arg ? KERNEL_PIT_TICK_RATE / arg : 0;
+
+ tprint_arg_next();
+ PRINT_VAL_U(arg);
+ if (xlat_verbose(xlat_verbosity) != XLAT_STYLE_RAW) {
+ if (freq)
+ tprintf_comment("%u Hz", freq);
+ else
+ tprints_comment("off");
+ }
+
+ return RVAL_IOCTL_DECODED;
+}
+
+static int
+kd_mk_tone(struct tcb *const tcp, const unsigned int arg)
+{
+ unsigned int ticks = arg >> 16;
+ unsigned int count = arg & 0xFFFF;
+ unsigned int freq = ticks && count ? KERNEL_PIT_TICK_RATE / count : 0;
+
+ tprint_arg_next();
+ if (ticks)
+ tprintf("%u<<16|%u", ticks, count);
+ else
+ PRINT_VAL_U(count);
+
+ if (xlat_verbose(xlat_verbosity) != XLAT_STYLE_RAW) {
+ if (freq)
+ tprintf_comment("%u Hz, %u ms", freq, ticks);
+ else
+ tprints_comment("off");
+ }
+
+ return RVAL_IOCTL_DECODED;
+}
+
+static void
+print_leds(struct tcb *const tcp, const kernel_ulong_t arg,
+ const bool get, const bool dflt)
+{
+ unsigned char val;
+
+ if (get) {
+ if (umove_or_printaddr(tcp, arg, &val))
+ return;
+ } else {
+ val = arg;
+ }
+
+ if (get)
+ tprint_indirect_begin();
+ printflags(dflt ? kd_default_led_flags : kd_led_flags, val,
+ "LED_???");
+ if (get)
+ tprint_indirect_end();
+}
+
+static int
+kd_leds(struct tcb *const tcp, const unsigned int code,
+ const kernel_ulong_t arg)
+{
+ bool get = false;
+ bool dflt = false;
+
+ switch (code) {
+ case KDGETLED:
+ case KDGKBLED:
+ get = true;
+ }
+
+ switch (code) {
+ case KDGKBLED:
+ case KDSKBLED:
+ dflt = true;
+ }
+
+ if (entering(tcp)) {
+ tprint_arg_next();
+
+ if (get)
+ return 0;
+ }
+
+ print_leds(tcp, arg, get, dflt);
+
+ return RVAL_IOCTL_DECODED;
+}
+
+static int
+kd_get_kb_type(struct tcb *const tcp, const kernel_ulong_t arg)
+{
+ unsigned char val;
+
+ if (entering(tcp)) {
+ tprint_arg_next();
+ return 0;
+ }
+
+ if (umove_or_printaddr(tcp, arg, &val))
+ return RVAL_IOCTL_DECODED;
+
+ tprint_indirect_begin();
+ printxval(kd_kbd_types, val, "KB_???");
+ tprint_indirect_end();
+
+ return RVAL_IOCTL_DECODED;
+}
+
+static int
+kd_io(struct tcb *const tcp, kernel_ulong_t arg)
+{
+ enum { GPFIRST = 0x3b4, GPLAST = 0x3df };
+
+ tprint_arg_next();
+ PRINT_VAL_X(arg);
+
+ if (arg >= GPFIRST && arg <= GPLAST
+ && xlat_verbose(xlat_verbosity) != XLAT_STYLE_RAW)
+ tprintf_comment("GPFIRST + %" PRI_klu, arg - GPFIRST);
+
+ return RVAL_IOCTL_DECODED;
+}
+
+static int
+kd_set_mode(struct tcb *const tcp, const kernel_ulong_t arg)
+{
+ tprint_arg_next();
+ printxval(kd_modes, arg, "KD_???");
+
+ return RVAL_IOCTL_DECODED;
+}
+
+static int
+kd_get_mode(struct tcb *const tcp, const kernel_ulong_t arg)
+{
+ unsigned int val;
+
+ if (entering(tcp)) {
+ tprint_arg_next();
+ return 0;
+ }
+
+ if (umove_or_printaddr(tcp, arg, &val))
+ return RVAL_IOCTL_DECODED;
+
+ tprint_indirect_begin();
+ printxval(kd_modes, val, "KD_???");
+ tprint_indirect_end();
+
+ return RVAL_IOCTL_DECODED;
+}
+
+static int
+kd_screen_map(struct tcb *const tcp, const kernel_ulong_t arg, const bool get)
+{
+ if (entering(tcp)) {
+ tprint_arg_next();
+
+ if (get)
+ return 0;
+ }
+
+ if (entering(tcp) || !syserror(tcp))
+ printstr_ex(tcp, arg, KERNEL_E_TABSZ, QUOTE_FORCE_HEX);
+ else
+ printaddr(arg);
+
+ return RVAL_IOCTL_DECODED;
+}
+
+static bool
+print_scrmap_array_member(struct tcb *tcp, void *elem_buf,
+ size_t elem_size, void *data)
+{
+ unsigned short val = *(unsigned short *) elem_buf;
+
+ if ((xlat_verbose(xlat_verbosity) != XLAT_STYLE_ABBREV) ||
+ ((val & ~UNI_DIRECT_MASK) != UNI_DIRECT_BASE))
+ PRINT_VAL_X(val);
+
+ if (xlat_verbose(xlat_verbosity) == XLAT_STYLE_RAW)
+ return true;
+
+ if ((val & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE)
+ (xlat_verbose(xlat_verbosity) == XLAT_STYLE_VERBOSE
+ ? tprintf_comment : tprintf)("UNI_DIRECT_BASE+%#hx",
+ val & UNI_DIRECT_MASK);
+
+ return true;
+}
+
+static int
+kd_uni_screen_map(struct tcb *const tcp, const kernel_ulong_t arg,
+ const bool get)
+{
+ unsigned short elem;
+
+ if (entering(tcp)) {
+ tprint_arg_next();
+
+ if (get)
+ return 0;
+ }
+
+ print_array(tcp, arg, KERNEL_E_TABSZ, &elem, sizeof(elem),
+ tfetch_mem, print_scrmap_array_member, 0);
+
+ return RVAL_IOCTL_DECODED;
+}
+
+static int
+kd_set_kbd_mode(struct tcb *const tcp, const unsigned int arg)
+{
+ tprint_arg_next();
+ printxval_d(kd_kbd_modes, arg, "K_???");
+
+ return RVAL_IOCTL_DECODED;
+}
+
+static int
+kd_get_kbd_mode(struct tcb *const tcp, const kernel_ulong_t arg)
+{
+ unsigned int val;
+
+ if (entering(tcp)) {
+ tprint_arg_next();
+ return 0;
+ }
+
+ if (umove_or_printaddr(tcp, arg, &val))
+ return RVAL_IOCTL_DECODED;
+
+ tprint_indirect_begin();
+ printxval_d(kd_kbd_modes, val, "K_???");
+ tprint_indirect_end();
+
+ return RVAL_IOCTL_DECODED;
+}
+
+static int
+kd_kbd_entry(struct tcb *const tcp, const kernel_ulong_t arg, const bool get)
+{
+ static const struct xlat *xlat_tables[] = {
+ /* KT_LATIN */
+ [KT_FN] = kd_key_fn_keys,
+ [KT_SPEC] = kd_key_spec_keys,
+ [KT_PAD] = kd_key_pad_keys,
+ [KT_DEAD] = kd_key_dead_keys,
+ /* KT_CONS */
+ [KT_CUR] = kd_key_cur_keys,
+ [KT_SHIFT] = kd_key_shift_keys,
+ /* KT_META */
+ [KT_ASCII] = kd_key_ascii_keys,
+ [KT_LOCK] = kd_key_lock_keys,
+ /* KT_LETTER */
+ [KT_SLOCK] = kd_key_slock_keys,
+ /* KT_DEAD2 */
+ [KT_BRL] = kd_key_brl_keys,
+ };
+
+ struct kbentry val;
+ unsigned char ktyp;
+ unsigned char kval;
+ const char *str = NULL;
+
+ if (entering(tcp)) {
+ tprint_arg_next();
+
+ if (umoven(tcp, arg, offsetofend(struct kbentry, kb_index),
+ &val)) {
+ printaddr(arg);
+ return RVAL_IOCTL_DECODED;
+ }
+
+ tprint_struct_begin();
+
+ const char *keymap_str = xlookup(kd_key_tables, val.kb_table);
+
+ if (keymap_str) {
+ tprints_field_name("kb_table");
+ print_xlat_ex(val.kb_table, keymap_str,
+ XLAT_STYLE_DEFAULT);
+ } else {
+ PRINT_FIELD_FLAGS(val, kb_table, kd_keymap_flags,
+ "K_???");
+ }
+
+ tprint_struct_next();
+ PRINT_FIELD_U(val, kb_index);
+
+ if (get)
+ return 0;
+ } else if (syserror(tcp)) {
+ goto out;
+ }
+
+ tprint_struct_next();
+ if (umove(tcp, arg + offsetof(struct kbentry, kb_value),
+ &val.kb_value)) {
+ tprints_field_name("kb_value");
+ tprint_unavailable();
+ goto out;
+ }
+
+ PRINT_FIELD_X(val, kb_value);
+
+ if (xlat_verbose(xlat_verbosity) == XLAT_STYLE_RAW)
+ goto out;
+
+ ktyp = KTYP(val.kb_value);
+ kval = KVAL(val.kb_value);
+
+ if (ktyp < ARRAY_SIZE(xlat_tables) && xlat_tables[ktyp])
+ str = xlookup(xlat_tables[ktyp], val.kb_value);
+
+ if (str) {
+ tprints_comment(str);
+ } else {
+ tprint_comment_begin();
+ tprints_arg_begin("K");
+ printxvals_ex(ktyp, NULL, XLAT_STYLE_ABBREV,
+ kd_key_types, NULL);
+ tprint_arg_next();
+
+ switch (ktyp) {
+ case KT_LATIN:
+ case KT_META:
+ case KT_LETTER:
+ case KT_DEAD2:
+ print_char(kval, SCF_QUOTES | SCF_ESC_WS);
+ break;
+ default:
+ PRINT_VAL_X(kval);
+ }
+
+ tprint_arg_end();
+ tprint_comment_end();
+ }
+
+out:
+ tprint_struct_end();
+
+ return RVAL_IOCTL_DECODED;
+}
+
+static int
+kd_kbd_str_entry(struct tcb *const tcp, const kernel_ulong_t arg,
+ const bool get)
+{
+ struct kbsentry val;
+
+ if (entering(tcp)) {
+ tprint_arg_next();
+
+ if (umove_or_printaddr(tcp, arg, &(val.kb_func)))
+ return RVAL_IOCTL_DECODED;
+
+ tprint_struct_begin();
+ PRINT_FIELD_XVAL(val, kb_func, kd_key_fn_key_vals,
+ "KVAL(K_???"")");
+
+ if (get)
+ return 0;
+ } else if (syserror(tcp)) {
+ goto out;
+ }
+
+ tprint_struct_next();
+ tprints_field_name("kb_string");
+
+ int ret = umovestr(tcp, arg + offsetof(struct kbsentry, kb_string),
+ sizeof(val.kb_string), (char *) val.kb_string);
+
+ if (ret < 0) {
+ tprint_unavailable();
+ goto out;
+ }
+
+ if (print_quoted_string((char *) val.kb_string,
+ MIN(max_strlen,
+ (unsigned int) ret ?: sizeof(val.kb_string)),
+ QUOTE_OMIT_TRAILING_0))
+ tprint_more_data_follows();
+
+out:
+ tprint_struct_end();
+
+ return RVAL_IOCTL_DECODED;
+}
+
+static bool
+print_kbdiacr_array_member(struct tcb *tcp, void *elem_buf,
+ size_t elem_size, void *data)
+{
+ struct kbdiacr *val = elem_buf;
+
+ tprint_struct_begin();
+ PRINT_FIELD_CHAR(*val, diacr, SCF_QUOTES | SCF_ESC_WS);
+ tprint_struct_next();
+ PRINT_FIELD_CHAR(*val, base, SCF_QUOTES | SCF_ESC_WS);
+ tprint_struct_next();
+ PRINT_FIELD_CHAR(*val, result, SCF_QUOTES | SCF_ESC_WS);
+ tprint_struct_end();
+
+ return true;
+}
+
+static int
+kd_diacr(struct tcb *const tcp, const kernel_ulong_t arg, const bool get)
+{
+ unsigned int kb_cnt; /* struct kbdiacrs.kb_cnt */
+ struct kbdiacr elem;
+
+ if (entering(tcp)) {
+ tprint_arg_next();
+
+ if (get)
+ return 0;
+ }
+
+ if (umove_or_printaddr(tcp, arg, &kb_cnt))
+ return RVAL_IOCTL_DECODED;
+
+ tprint_struct_begin();
+ tprints_field_name("kb_cnt");
+ PRINT_VAL_U(kb_cnt);
+ tprint_struct_next();
+ tprints_field_name("kbdiacr");
+ print_array_ex(tcp, arg + offsetof(struct kbdiacrs, kbdiacr),
+ MIN(kb_cnt, KERNEL_MAX_DIACR), &elem, sizeof(elem),
+ tfetch_mem, print_kbdiacr_array_member, 0,
+ kb_cnt > KERNEL_MAX_DIACR ? PAF_ARRAY_TRUNCATED : 0,
+ NULL, NULL);
+ tprint_struct_end();
+
+ return RVAL_IOCTL_DECODED;
+}
+
+static bool
+print_kbdiacruc_array_member(struct tcb *tcp, void *elem_buf,
+ size_t elem_size, void *data)
+{
+ struct kbdiacruc *val = elem_buf;
+
+ tprint_struct_begin();
+ PRINT_FIELD_X(*val, diacr);
+ tprint_struct_next();
+ PRINT_FIELD_X(*val, base);
+ tprint_struct_next();
+ PRINT_FIELD_X(*val, result);
+ tprint_struct_end();
+
+ return true;
+}
+
+static int
+kd_diacr_uc(struct tcb *const tcp, const kernel_ulong_t arg, const bool get)
+{
+ unsigned int kb_cnt; /* struct kbdiacrs.kb_cnt */
+ struct kbdiacruc elem;
+
+ if (entering(tcp)) {
+ tprint_arg_next();
+
+ if (get)
+ return 0;
+ }
+
+ if (umove_or_printaddr(tcp, arg, &kb_cnt))
+ return RVAL_IOCTL_DECODED;
+
+ tprint_struct_begin();
+ tprints_field_name("kb_cnt");
+ PRINT_VAL_U(kb_cnt);
+ tprint_struct_next();
+ tprints_field_name("kbdiacruc");
+ print_array_ex(tcp, arg + offsetof(struct kbdiacrsuc, kbdiacruc),
+ MIN(kb_cnt, KERNEL_MAX_DIACR), &elem, sizeof(elem),
+ tfetch_mem, print_kbdiacruc_array_member, 0,
+ kb_cnt > KERNEL_MAX_DIACR ? PAF_ARRAY_TRUNCATED : 0,
+ NULL, NULL);
+ tprint_struct_end();
+
+ return RVAL_IOCTL_DECODED;
+}
+
+static int
+kd_keycode(struct tcb *const tcp, const kernel_ulong_t arg, const bool get)
+{
+ struct kbkeycode val;
+
+ if (entering(tcp)) {
+ tprint_arg_next();
+
+ if (umove_or_printaddr(tcp, arg, &val))
+ return RVAL_IOCTL_DECODED;
+
+ tprint_struct_begin();
+ PRINT_FIELD_X(val, scancode);
+ tprint_struct_next();
+ PRINT_FIELD_X(val, keycode);
+
+ if (get)
+ return 0;
+
+ goto end;
+ }
+
+ /* exiting */
+ if (syserror(tcp) ||
+ umove(tcp, arg + offsetof(struct kbkeycode, keycode), &val.keycode))
+ {
+ tprint_struct_end();
+ return RVAL_IOCTL_DECODED;
+ }
+
+ tprint_value_changed();
+ PRINT_VAL_X(val.keycode);
+
+end:
+ tprint_struct_end();
+
+ return RVAL_IOCTL_DECODED;
+}
+
+static int
+kd_sigaccept(struct tcb *const tcp, const kernel_ulong_t arg)
+{
+ tprint_arg_next();
+
+ if (arg < INT_MAX)
+ printsignal(arg);
+ else
+ PRINT_VAL_U(arg);
+
+ return RVAL_IOCTL_DECODED;
+}
+
+static void
+print_kbd_repeat(struct kbd_repeat *val)
+{
+ tprint_struct_begin();
+ PRINT_FIELD_D(*val, delay);
+ tprint_struct_next();
+ PRINT_FIELD_D(*val, period);
+ tprint_struct_end();
+}
+
+static int
+kd_kbdrep(struct tcb *const tcp, const kernel_ulong_t arg)
+{
+ struct kbd_repeat val;
+
+ if (entering(tcp)) {
+ tprint_arg_next();
+
+ if (umove_or_printaddr(tcp, arg, &val))
+ return RVAL_IOCTL_DECODED;
+
+ print_kbd_repeat(&val);
+
+ return 0;
+ }
+
+ /* exiting */
+ if (syserror(tcp) || umove(tcp, arg, &val))
+ return RVAL_IOCTL_DECODED;
+
+ tprint_value_changed();
+
+ print_kbd_repeat(&val);
+
+ return RVAL_IOCTL_DECODED;
+}
+
+static int
+kd_font(struct tcb *const tcp, const kernel_ulong_t arg, const bool get)
+{
+ if (entering(tcp)) {
+ tprint_arg_next();
+
+ if (get)
+ return 0;
+ }
+
+ /*
+ * [GP]IO_FONT are equivalent to KDFONTOP with width == 8,
+ * height == 32, and charcount == 256, so the total size
+ * is (width + 7) / 8 * height * charcount == 8192.
+ */
+ if (exiting(tcp) && syserror(tcp))
+ printaddr(arg);
+ else
+ printstr_ex(tcp, arg, 8192, QUOTE_FORCE_HEX);
+
+ return RVAL_IOCTL_DECODED;
+}
+
+static int
+kd_kbmeta(struct tcb *const tcp, const kernel_ulong_t arg, const bool get)
+{
+ unsigned int val;
+
+ if (entering(tcp)) {
+ tprint_arg_next();
+
+ if (get)
+ return 0;
+ }
+
+ if (get) {
+ if (umove_or_printaddr(tcp, arg, &val))
+ return RVAL_IOCTL_DECODED;
+ } else {
+ val = arg;
+ }
+
+ if (get)
+ tprint_indirect_begin();
+ printxval(kd_meta_vals, val, "K_???");
+ if (get)
+ tprint_indirect_end();
+
+ return RVAL_IOCTL_DECODED;
+}
+
+static int
+kd_unimapclr(struct tcb *const tcp, const kernel_ulong_t arg)
+{
+ struct unimapinit umi;
+
+ tprint_arg_next();
+
+ if (umove_or_printaddr(tcp, arg, &umi))
+ return RVAL_IOCTL_DECODED;
+
+ tprint_struct_begin();
+ PRINT_FIELD_U(umi, advised_hashsize);
+ tprint_struct_next();
+ PRINT_FIELD_U(umi, advised_hashstep);
+ tprint_struct_next();
+ PRINT_FIELD_U(umi, advised_hashlevel);
+ tprint_struct_end();
+
+ return RVAL_IOCTL_DECODED;
+}
+
+static int
+kd_cmap(struct tcb *const tcp, const kernel_ulong_t arg, const bool get)
+{
+ if (entering(tcp)) {
+ tprint_arg_next();
+
+ if (get)
+ return 0;
+ } else {
+ if (syserror(tcp)) {
+ printaddr(arg);
+
+ return RVAL_IOCTL_DECODED;
+ }
+ }
+
+ printstr_ex(tcp, arg, 3 * 16, QUOTE_FORCE_HEX);
+
+ return RVAL_IOCTL_DECODED;
+}
+
+int
+kd_ioctl(struct tcb *const tcp, const unsigned int code,
+ kernel_ulong_t arg)
+{
+ arg = truncate_kulong_to_current_wordsize(arg);
+
+ switch (code) {
+ case KIOCSOUND:
+ return kiocsound(tcp, arg);
+
+ case KDMKTONE:
+ return kd_mk_tone(tcp, arg);
+
+ case KDGETLED:
+ case KDSETLED:
+ case KDGKBLED:
+ case KDSKBLED:
+ return kd_leds(tcp, code, arg);
+
+ case KDGKBTYPE:
+ return kd_get_kb_type(tcp, arg);
+
+ case KDADDIO:
+ case KDDELIO:
+ return kd_io(tcp, arg);
+
+ case KDSETMODE:
+ return kd_set_mode(tcp, arg);
+ case KDGETMODE:
+ return kd_get_mode(tcp, arg);
+
+ case GIO_SCRNMAP:
+ case PIO_SCRNMAP:
+ return kd_screen_map(tcp, arg, code == GIO_SCRNMAP);
+
+ case GIO_UNISCRNMAP:
+ case PIO_UNISCRNMAP:
+ return kd_uni_screen_map(tcp, arg, code == GIO_UNISCRNMAP);
+
+ case KDGKBMODE:
+ return kd_get_kbd_mode(tcp, arg);
+ case KDSKBMODE:
+ return kd_set_kbd_mode(tcp, arg);
+
+ case KDGKBENT:
+ case KDSKBENT:
+ return kd_kbd_entry(tcp, arg, code == KDGKBENT);
+
+ case KDGKBSENT:
+ case KDSKBSENT:
+ return kd_kbd_str_entry(tcp, arg, code == KDGKBSENT);
+
+ case KDGKBDIACR:
+ case KDSKBDIACR:
+ return kd_diacr(tcp, arg, code == KDGKBDIACR);
+
+ case KDGKBDIACRUC:
+ case KDSKBDIACRUC:
+ return kd_diacr_uc(tcp, arg, code == KDGKBDIACRUC);
+
+ case KDGETKEYCODE:
+ case KDSETKEYCODE:
+ return kd_keycode(tcp, arg, code == KDGETKEYCODE);
+
+ case KDSIGACCEPT:
+ return kd_sigaccept(tcp, arg);
+
+ case KDKBDREP:
+ return kd_kbdrep(tcp, arg);
+
+ case GIO_FONT:
+ case PIO_FONT:
+ return kd_font(tcp, arg, code == GIO_FONT);
+
+ case KDGKBMETA:
+ case KDSKBMETA:
+ return kd_kbmeta(tcp, arg, code == KDGKBMETA);
+
+ case PIO_UNIMAPCLR:
+ return kd_unimapclr(tcp, arg);
+
+ case GIO_CMAP:
+ case PIO_CMAP:
+ return kd_cmap(tcp, arg, code == GIO_CMAP);
+
+ /* no arguments */
+ case KDENABIO:
+ case KDDISABIO:
+ case KDMAPDISP:
+ case KDUNMAPDISP:
+ case PIO_FONTRESET:
+ return RVAL_IOCTL_DECODED;
+ }
+
+ /* GIO_UNIMAP, PIO_UNIMAP, GIO_FONTX, PIO_FONTX, KDFONTOP */
+ return kd_mpers_ioctl(tcp, code, arg);
+}
diff --git a/src/kd_mpers_ioctl.c b/src/kd_mpers_ioctl.c
new file mode 100644
index 000000000..b42269b6b
--- /dev/null
+++ b/src/kd_mpers_ioctl.c
@@ -0,0 +1,269 @@
+/*
+ * Support for decoding of personality-dependent VT ioctl commands.
+ *
+ * Copyright (c) 2019-2021 Eugene Syromyatnikov <evgsyr@gmail.com>
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "defs.h"
+
+#include <linux/kd.h>
+
+#include DEF_MPERS_TYPE(struct_unimapdesc)
+#include DEF_MPERS_TYPE(struct_consolefontdesc)
+#include DEF_MPERS_TYPE(struct_console_font)
+#include DEF_MPERS_TYPE(struct_console_font_op)
+
+typedef struct unimapdesc struct_unimapdesc;
+typedef struct consolefontdesc struct_consolefontdesc;
+typedef struct console_font struct_console_font;
+typedef struct console_font_op struct_console_font_op;
+
+#include MPERS_DEFS
+
+#include "print_fields.h"
+
+#include "xlat/kd_font_flags.h"
+#include "xlat/kd_font_ops.h"
+
+#define XLAT_MACROS_ONLY
+# include "xlat/kd_ioctl_cmds.h"
+#undef XLAT_MACROS_ONLY
+
+
+static bool
+print_unipair_array_member(struct tcb *tcp, void *elem_buf,
+ size_t elem_size, void *data)
+{
+ struct unipair *val = elem_buf;
+
+ tprint_struct_begin();
+ PRINT_FIELD_X(*val, unicode);
+ tprint_struct_next();
+ PRINT_FIELD_X(*val, fontpos);
+ tprint_struct_end();
+
+ return true;
+}
+
+static int
+kd_unimap(struct tcb *const tcp, const kernel_ulong_t arg, const bool get)
+{
+ struct_unimapdesc val;
+ struct unipair elem;
+ uint16_t cnt;
+
+ if (entering(tcp))
+ tprint_arg_next();
+
+ if (umove_or_printaddr_ignore_syserror(tcp, arg, &val)) {
+ if (exiting(tcp))
+ tprint_struct_end();
+
+ return RVAL_IOCTL_DECODED;
+ }
+
+ if (entering(tcp)) {
+ set_tcb_priv_ulong(tcp, val.entry_ct);
+ tprint_struct_begin();
+ PRINT_FIELD_U(val, entry_ct);
+
+ if (get)
+ return 0;
+ } else {
+ tprint_value_changed();
+ PRINT_VAL_U(val.entry_ct);
+ }
+
+ if (exiting(tcp) && syserror(tcp) && tcp->u_error != ENOMEM) {
+ tprint_struct_next();
+ PRINT_FIELD_PTR(val, entries);
+ tprint_struct_end();
+ return RVAL_IOCTL_DECODED;
+ }
+
+ cnt = entering(tcp) ? val.entry_ct : get_tcb_priv_ulong(tcp);
+
+ tprint_struct_next();
+ tprints_field_name("entries");
+ print_array(tcp, (mpers_ptr_t) val.entries, cnt, &elem, sizeof(elem),
+ tfetch_mem, print_unipair_array_member, 0);
+
+ tprint_struct_end();
+
+ return get && entering(tcp) ? 0 : RVAL_IOCTL_DECODED;
+}
+
+static void
+print_consolefontdesc(struct tcb *const tcp, const struct_consolefontdesc *cfd,
+ const bool get)
+{
+ tprint_struct_begin();
+ PRINT_FIELD_U(*cfd, charcount);
+ tprint_struct_next();
+ PRINT_FIELD_U(*cfd, charheight);
+ tprint_struct_next();
+ if (get) {
+ PRINT_FIELD_PTR(*cfd, chardata);
+ } else {
+ tprints_field_name("chardata");
+ printstr_ex(tcp, (mpers_ptr_t) cfd->chardata,
+ MIN(cfd->charcount, 512) * 32, QUOTE_FORCE_HEX);
+ }
+
+ tprint_struct_end();
+}
+
+static int
+kd_fontx(struct tcb *const tcp, const kernel_ulong_t arg, const bool get)
+{
+ struct_consolefontdesc val;
+
+ if (entering(tcp)) {
+ tprint_arg_next();
+
+ if (umove_or_printaddr(tcp, arg, &val))
+ return RVAL_IOCTL_DECODED;
+ } else {
+ if (syserror(tcp) || umove(tcp, arg, &val))
+ return RVAL_IOCTL_DECODED;
+
+ tprint_value_changed();
+ }
+
+ print_consolefontdesc(tcp, &val, get && entering(tcp));
+
+ return get && entering(tcp) ? 0 : RVAL_IOCTL_DECODED;
+}
+
+static void
+print_console_font_op(struct tcb *const tcp, const struct_console_font_op *cfo)
+{
+ enum { KERNEL_MAX_FONT_NAME = 32 };
+
+ tprint_struct_begin();
+
+ if (entering(tcp)) {
+ PRINT_FIELD_XVAL(*cfo, op, kd_font_ops, "KD_FONT_OP_???");
+
+ switch (cfo->op) {
+ case KD_FONT_OP_SET_DEFAULT:
+ case KD_FONT_OP_COPY:
+ break;
+ default:
+ tprint_struct_next();
+ PRINT_FIELD_FLAGS(*cfo, flags, kd_font_flags,
+ "KD_FONT_FLAG_???");
+ }
+
+ tprint_struct_next();
+ }
+
+ switch (cfo->op) {
+ case KD_FONT_OP_COPY:
+ PRINT_FIELD_U(*cfo, height);
+ break;
+ default:
+ PRINT_FIELD_U(*cfo, width);
+ tprint_struct_next();
+ PRINT_FIELD_U(*cfo, height);
+ }
+
+ switch (cfo->op) {
+ case KD_FONT_OP_SET_DEFAULT:
+ case KD_FONT_OP_COPY:
+ break;
+ default:
+ tprint_struct_next();
+ PRINT_FIELD_U(*cfo, charcount);
+ }
+
+ switch (cfo->op) {
+ case KD_FONT_OP_GET:
+ if (entering(tcp)) {
+ tprint_struct_next();
+ PRINT_FIELD_PTR(*cfo, data);
+ break;
+ }
+ ATTRIBUTE_FALLTHROUGH;
+
+ case KD_FONT_OP_SET:
+ tprint_struct_next();
+ tprints_field_name("data");
+ printstr_ex(tcp, (mpers_ptr_t) cfo->data,
+ ROUNDUP_DIV(MIN(cfo->width, 32), 8) * 32 *
+ MIN(cfo->charcount, 512),
+ QUOTE_FORCE_HEX);
+ break;
+
+ case KD_FONT_OP_SET_DEFAULT:
+ if (entering(tcp)) {
+ tprint_struct_next();
+ tprints_field_name("data");
+ printstr_ex(tcp, (mpers_ptr_t) cfo->data,
+ KERNEL_MAX_FONT_NAME,
+ QUOTE_0_TERMINATED
+ | QUOTE_EXPECT_TRAILING_0);
+ }
+ break;
+
+ case KD_FONT_OP_COPY:
+ break;
+
+ default:
+ tprint_struct_next();
+ PRINT_FIELD_PTR(*cfo, data);
+ }
+
+ tprint_struct_end();
+}
+
+static int
+kd_font_op(struct tcb *const tcp, const kernel_ulong_t arg)
+{
+ struct_console_font_op val;
+
+ if (entering(tcp)) {
+ tprint_arg_next();
+
+ if (umove_or_printaddr(tcp, arg, &val))
+ return RVAL_IOCTL_DECODED;
+ } else {
+ if (syserror(tcp) || umove(tcp, arg, &val))
+ return RVAL_IOCTL_DECODED;
+
+ tprint_value_changed();
+ }
+
+ print_console_font_op(tcp, &val);
+
+ switch (val.op) {
+ case KD_FONT_OP_SET:
+ case KD_FONT_OP_COPY:
+ return RVAL_IOCTL_DECODED;
+ }
+
+ return entering(tcp) ? 0 : RVAL_IOCTL_DECODED;
+}
+
+MPERS_PRINTER_DECL(int, kd_mpers_ioctl, struct tcb *const tcp,
+ const unsigned int code, const kernel_ulong_t arg)
+{
+ switch (code)
+ {
+ case GIO_UNIMAP:
+ case PIO_UNIMAP:
+ return kd_unimap(tcp, arg, code == GIO_UNIMAP);
+
+ case GIO_FONTX:
+ case PIO_FONTX:
+ return kd_fontx(tcp, arg, code == GIO_FONTX);
+
+ case KDFONTOP:
+ return kd_font_op(tcp, arg);
+ }
+
+ return RVAL_DECODED;
+}
diff --git a/src/xlat/kd_default_led_flags.in b/src/xlat/kd_default_led_flags.in
new file mode 100644
index 000000000..b0ab5a3ad
--- /dev/null
+++ b/src/xlat/kd_default_led_flags.in
@@ -0,0 +1,7 @@
+#unconditional
+LED_SCR
+LED_NUM
+LED_CAP
+LED_SCR<<4
+LED_NUM<<4
+LED_CAP<<4
diff --git a/src/xlat/kd_font_flags.in b/src/xlat/kd_font_flags.in
new file mode 100644
index 000000000..665d59a22
--- /dev/null
+++ b/src/xlat/kd_font_flags.in
@@ -0,0 +1,2 @@
+KD_FONT_FLAG_DONT_RECALC 0x1
+KD_FONT_FLAG_OLD 0x80000000
diff --git a/src/xlat/kd_font_ops.in b/src/xlat/kd_font_ops.in
new file mode 100644
index 000000000..29d336882
--- /dev/null
+++ b/src/xlat/kd_font_ops.in
@@ -0,0 +1,5 @@
+#value_indexed
+KD_FONT_OP_SET 0
+KD_FONT_OP_GET 1
+KD_FONT_OP_SET_DEFAULT 2
+KD_FONT_OP_COPY 3
diff --git a/src/xlat/kd_ioctl_cmds.in b/src/xlat/kd_ioctl_cmds.in
new file mode 100644
index 000000000..3f2ad3e09
--- /dev/null
+++ b/src/xlat/kd_ioctl_cmds.in
@@ -0,0 +1,48 @@
+#sorted
+/* include/uapi/linux/kd.h */
+KIOCSOUND 0x4B2F
+KDMKTONE 0x4B30
+KDGETLED 0x4B31
+KDSETLED 0x4B32
+KDGKBTYPE 0x4B33
+KDADDIO 0x4B34
+KDDELIO 0x4B35
+KDENABIO 0x4B36
+KDDISABIO 0x4B37
+KDSETMODE 0x4B3A
+KDGETMODE 0x4B3B
+KDMAPDISP 0x4B3C
+KDUNMAPDISP 0x4B3D
+GIO_SCRNMAP 0x4B40
+PIO_SCRNMAP 0x4B41
+KDGKBMODE 0x4B44
+KDSKBMODE 0x4B45
+KDGKBENT 0x4B46
+KDSKBENT 0x4B47
+KDGKBSENT 0x4B48
+KDSKBSENT 0x4B49
+KDGKBDIACR 0x4B4A
+KDSKBDIACR 0x4B4B
+KDGETKEYCODE 0x4B4C
+KDSETKEYCODE 0x4B4D
+KDSIGACCEPT 0x4B4E
+KDKBDREP 0x4B52
+GIO_FONT 0x4B60
+PIO_FONT 0x4B61
+KDGKBMETA 0x4B62
+KDSKBMETA 0x4B63
+KDGKBLED 0x4B64
+KDSKBLED 0x4B65
+GIO_UNIMAP 0x4B66
+PIO_UNIMAP 0x4B67
+PIO_UNIMAPCLR 0x4B68
+GIO_UNISCRNMAP 0x4B69
+PIO_UNISCRNMAP 0x4B6A
+GIO_FONTX 0x4B6B
+PIO_FONTX 0x4B6C
+PIO_FONTRESET 0x4B6D
+GIO_CMAP 0x4B70
+PIO_CMAP 0x4B71
+KDFONTOP 0x4B72
+KDGKBDIACRUC 0x4BFA
+KDSKBDIACRUC 0x4BFB
diff --git a/src/xlat/kd_kbd_modes.in b/src/xlat/kd_kbd_modes.in
new file mode 100644
index 000000000..a38cc0e3c
--- /dev/null
+++ b/src/xlat/kd_kbd_modes.in
@@ -0,0 +1,6 @@
+#value_indexed
+K_RAW 0
+K_XLATE 1
+K_MEDIUMRAW 2
+K_UNICODE 3
+K_OFF 4
diff --git a/src/xlat/kd_kbd_types.in b/src/xlat/kd_kbd_types.in
new file mode 100644
index 000000000..23516e233
--- /dev/null
+++ b/src/xlat/kd_kbd_types.in
@@ -0,0 +1,3 @@
+KB_84 0x1
+KB_101 0x2
+KB_OTHER 0x3
diff --git a/src/xlat/kd_key_ascii_keys.in b/src/xlat/kd_key_ascii_keys.in
new file mode 100644
index 000000000..8f15c54e7
--- /dev/null
+++ b/src/xlat/kd_key_ascii_keys.in
@@ -0,0 +1,27 @@
+#sorted
+K_ASC0 K(KT_ASCII,0)
+K_ASC1 K(KT_ASCII,1)
+K_ASC2 K(KT_ASCII,2)
+K_ASC3 K(KT_ASCII,3)
+K_ASC4 K(KT_ASCII,4)
+K_ASC5 K(KT_ASCII,5)
+K_ASC6 K(KT_ASCII,6)
+K_ASC7 K(KT_ASCII,7)
+K_ASC8 K(KT_ASCII,8)
+K_ASC9 K(KT_ASCII,9)
+K_HEX0 K(KT_ASCII,10)
+K_HEX1 K(KT_ASCII,11)
+K_HEX2 K(KT_ASCII,12)
+K_HEX3 K(KT_ASCII,13)
+K_HEX4 K(KT_ASCII,14)
+K_HEX5 K(KT_ASCII,15)
+K_HEX6 K(KT_ASCII,16)
+K_HEX7 K(KT_ASCII,17)
+K_HEX8 K(KT_ASCII,18)
+K_HEX9 K(KT_ASCII,19)
+K_HEXa K(KT_ASCII,20)
+K_HEXb K(KT_ASCII,21)
+K_HEXc K(KT_ASCII,22)
+K_HEXd K(KT_ASCII,23)
+K_HEXe K(KT_ASCII,24)
+K_HEXf K(KT_ASCII,25)
diff --git a/src/xlat/kd_key_brl_keys.in b/src/xlat/kd_key_brl_keys.in
new file mode 100644
index 000000000..1ea09bfaf
--- /dev/null
+++ b/src/xlat/kd_key_brl_keys.in
@@ -0,0 +1,12 @@
+#sorted
+K_BRL_BLANK K(KT_BRL, 0)
+K_BRL_DOT1 K(KT_BRL, 1)
+K_BRL_DOT2 K(KT_BRL, 2)
+K_BRL_DOT3 K(KT_BRL, 3)
+K_BRL_DOT4 K(KT_BRL, 4)
+K_BRL_DOT5 K(KT_BRL, 5)
+K_BRL_DOT6 K(KT_BRL, 6)
+K_BRL_DOT7 K(KT_BRL, 7)
+K_BRL_DOT8 K(KT_BRL, 8)
+K_BRL_DOT9 K(KT_BRL, 9)
+K_BRL_DOT10 K(KT_BRL, 10)
diff --git a/src/xlat/kd_key_cur_keys.in b/src/xlat/kd_key_cur_keys.in
new file mode 100644
index 000000000..51d1458fc
--- /dev/null
+++ b/src/xlat/kd_key_cur_keys.in
@@ -0,0 +1,5 @@
+#sorted
+K_DOWN K(KT_CUR,0)
+K_LEFT K(KT_CUR,1)
+K_RIGHT K(KT_CUR,2)
+K_UP K(KT_CUR,3)
diff --git a/src/xlat/kd_key_dead_keys.in b/src/xlat/kd_key_dead_keys.in
new file mode 100644
index 000000000..9d08fb22b
--- /dev/null
+++ b/src/xlat/kd_key_dead_keys.in
@@ -0,0 +1,28 @@
+#sorted
+K_DGRAVE K(KT_DEAD,0)
+K_DACUTE K(KT_DEAD,1)
+K_DCIRCM K(KT_DEAD,2)
+K_DTILDE K(KT_DEAD,3)
+K_DDIERE K(KT_DEAD,4)
+K_DCEDIL K(KT_DEAD,5)
+K_DMACRON K(KT_DEAD,6)
+K_DBREVE K(KT_DEAD,7)
+K_DABDOT K(KT_DEAD,8)
+K_DABRING K(KT_DEAD,9)
+K_DDBACUTE K(KT_DEAD,10)
+K_DCARON K(KT_DEAD,11)
+K_DOGONEK K(KT_DEAD,12)
+K_DIOTA K(KT_DEAD,13)
+K_DVOICED K(KT_DEAD,14)
+K_DSEMVOICED K(KT_DEAD,15)
+K_DBEDOT K(KT_DEAD,16)
+K_DHOOK K(KT_DEAD,17)
+K_DHORN K(KT_DEAD,18)
+K_DSTROKE K(KT_DEAD,19)
+K_DABCOMMA K(KT_DEAD,20)
+K_DABREVCOMMA K(KT_DEAD,21)
+K_DDBGRAVE K(KT_DEAD,22)
+K_DINVBREVE K(KT_DEAD,23)
+K_DBECOMMA K(KT_DEAD,24)
+K_DCURRENCY K(KT_DEAD,25)
+K_DGREEK K(KT_DEAD,26)
diff --git a/src/xlat/kd_key_fn_key_vals.in b/src/xlat/kd_key_fn_key_vals.in
new file mode 100644
index 000000000..a79ea1b07
--- /dev/null
+++ b/src/xlat/kd_key_fn_key_vals.in
@@ -0,0 +1,258 @@
+#value_indexed
+#unconditional
+KVAL(K_F1)
+KVAL(K_F2)
+KVAL(K_F3)
+KVAL(K_F4)
+KVAL(K_F5)
+KVAL(K_F6)
+KVAL(K_F7)
+KVAL(K_F8)
+KVAL(K_F9)
+KVAL(K_F10)
+KVAL(K_F11)
+KVAL(K_F12)
+KVAL(K_F13)
+KVAL(K_F14)
+KVAL(K_F15)
+KVAL(K_F16)
+KVAL(K_F17)
+KVAL(K_F18)
+KVAL(K_F19)
+KVAL(K_F20)
+KVAL(K_FIND)
+KVAL(K_INSERT)
+KVAL(K_REMOVE)
+KVAL(K_SELECT)
+KVAL(K_PGUP)
+KVAL(K_PGDN)
+KVAL(K_MACRO)
+KVAL(K_HELP)
+KVAL(K_DO)
+KVAL(K_PAUSE)
+KVAL(K_F21)
+KVAL(K_F22)
+KVAL(K_F23)
+KVAL(K_F24)
+KVAL(K_F25)
+KVAL(K_F26)
+KVAL(K_F27)
+KVAL(K_F28)
+KVAL(K_F29)
+KVAL(K_F30)
+KVAL(K_F31)
+KVAL(K_F32)
+KVAL(K_F33)
+KVAL(K_F34)
+KVAL(K_F35)
+KVAL(K_F36)
+KVAL(K_F37)
+KVAL(K_F38)
+KVAL(K_F39)
+KVAL(K_F40)
+KVAL(K_F41)
+KVAL(K_F42)
+KVAL(K_F43)
+KVAL(K_F44)
+KVAL(K_F45)
+KVAL(K_F46)
+KVAL(K_F47)
+KVAL(K_F48)
+KVAL(K_F49)
+KVAL(K_F50)
+KVAL(K_F51)
+KVAL(K_F52)
+KVAL(K_F53)
+KVAL(K_F54)
+KVAL(K_F55)
+KVAL(K_F56)
+KVAL(K_F57)
+KVAL(K_F58)
+KVAL(K_F59)
+KVAL(K_F60)
+KVAL(K_F61)
+KVAL(K_F62)
+KVAL(K_F63)
+KVAL(K_F64)
+KVAL(K_F65)
+KVAL(K_F66)
+KVAL(K_F67)
+KVAL(K_F68)
+KVAL(K_F69)
+KVAL(K_F70)
+KVAL(K_F71)
+KVAL(K_F72)
+KVAL(K_F73)
+KVAL(K_F74)
+KVAL(K_F75)
+KVAL(K_F76)
+KVAL(K_F77)
+KVAL(K_F78)
+KVAL(K_F79)
+KVAL(K_F80)
+KVAL(K_F81)
+KVAL(K_F82)
+KVAL(K_F83)
+KVAL(K_F84)
+KVAL(K_F85)
+KVAL(K_F86)
+KVAL(K_F87)
+KVAL(K_F88)
+KVAL(K_F89)
+KVAL(K_F90)
+KVAL(K_F91)
+KVAL(K_F92)
+KVAL(K_F93)
+KVAL(K_F94)
+KVAL(K_F95)
+KVAL(K_F96)
+KVAL(K_F97)
+KVAL(K_F98)
+KVAL(K_F99)
+KVAL(K_F100)
+KVAL(K_F101)
+KVAL(K_F102)
+KVAL(K_F103)
+KVAL(K_F104)
+KVAL(K_F105)
+KVAL(K_F106)
+KVAL(K_F107)
+KVAL(K_F108)
+KVAL(K_F109)
+KVAL(K_F110)
+KVAL(K_F111)
+KVAL(K_F112)
+KVAL(K_F113)
+KVAL(K_F114)
+KVAL(K_F115)
+KVAL(K_F116)
+KVAL(K_F117)
+KVAL(K_F118)
+KVAL(K_F119)
+KVAL(K_F120)
+KVAL(K_F121)
+KVAL(K_F122)
+KVAL(K_F123)
+KVAL(K_F124)
+KVAL(K_F125)
+KVAL(K_F126)
+KVAL(K_F127)
+KVAL(K_F128)
+KVAL(K_F129)
+KVAL(K_F130)
+KVAL(K_F131)
+KVAL(K_F132)
+KVAL(K_F133)
+KVAL(K_F134)
+KVAL(K_F135)
+KVAL(K_F136)
+KVAL(K_F137)
+KVAL(K_F138)
+KVAL(K_F139)
+KVAL(K_F140)
+KVAL(K_F141)
+KVAL(K_F142)
+KVAL(K_F143)
+KVAL(K_F144)
+KVAL(K_F145)
+KVAL(K_F146)
+KVAL(K_F147)
+KVAL(K_F148)
+KVAL(K_F149)
+KVAL(K_F150)
+KVAL(K_F151)
+KVAL(K_F152)
+KVAL(K_F153)
+KVAL(K_F154)
+KVAL(K_F155)
+KVAL(K_F156)
+KVAL(K_F157)
+KVAL(K_F158)
+KVAL(K_F159)
+KVAL(K_F160)
+KVAL(K_F161)
+KVAL(K_F162)
+KVAL(K_F163)
+KVAL(K_F164)
+KVAL(K_F165)
+KVAL(K_F166)
+KVAL(K_F167)
+KVAL(K_F168)
+KVAL(K_F169)
+KVAL(K_F170)
+KVAL(K_F171)
+KVAL(K_F172)
+KVAL(K_F173)
+KVAL(K_F174)
+KVAL(K_F175)
+KVAL(K_F176)
+KVAL(K_F177)
+KVAL(K_F178)
+KVAL(K_F179)
+KVAL(K_F180)
+KVAL(K_F181)
+KVAL(K_F182)
+KVAL(K_F183)
+KVAL(K_F184)
+KVAL(K_F185)
+KVAL(K_F186)
+KVAL(K_F187)
+KVAL(K_F188)
+KVAL(K_F189)
+KVAL(K_F190)
+KVAL(K_F191)
+KVAL(K_F192)
+KVAL(K_F193)
+KVAL(K_F194)
+KVAL(K_F195)
+KVAL(K_F196)
+KVAL(K_F197)
+KVAL(K_F198)
+KVAL(K_F199)
+KVAL(K_F200)
+KVAL(K_F201)
+KVAL(K_F202)
+KVAL(K_F203)
+KVAL(K_F204)
+KVAL(K_F205)
+KVAL(K_F206)
+KVAL(K_F207)
+KVAL(K_F208)
+KVAL(K_F209)
+KVAL(K_F210)
+KVAL(K_F211)
+KVAL(K_F212)
+KVAL(K_F213)
+KVAL(K_F214)
+KVAL(K_F215)
+KVAL(K_F216)
+KVAL(K_F217)
+KVAL(K_F218)
+KVAL(K_F219)
+KVAL(K_F220)
+KVAL(K_F221)
+KVAL(K_F222)
+KVAL(K_F223)
+KVAL(K_F224)
+KVAL(K_F225)
+KVAL(K_F226)
+KVAL(K_F227)
+KVAL(K_F228)
+KVAL(K_F229)
+KVAL(K_F230)
+KVAL(K_F231)
+KVAL(K_F232)
+KVAL(K_F233)
+KVAL(K_F234)
+KVAL(K_F235)
+KVAL(K_F236)
+KVAL(K_F237)
+KVAL(K_F238)
+KVAL(K_F239)
+KVAL(K_F240)
+KVAL(K_F241)
+KVAL(K_F242)
+KVAL(K_F243)
+KVAL(K_F244)
+KVAL(K_F245)
+KVAL(K_UNDO)
diff --git a/src/xlat/kd_key_fn_keys.in b/src/xlat/kd_key_fn_keys.in
new file mode 100644
index 000000000..65a29f2f5
--- /dev/null
+++ b/src/xlat/kd_key_fn_keys.in
@@ -0,0 +1,257 @@
+#sorted
+K_F1 K(KT_FN,0)
+K_F2 K(KT_FN,1)
+K_F3 K(KT_FN,2)
+K_F4 K(KT_FN,3)
+K_F5 K(KT_FN,4)
+K_F6 K(KT_FN,5)
+K_F7 K(KT_FN,6)
+K_F8 K(KT_FN,7)
+K_F9 K(KT_FN,8)
+K_F10 K(KT_FN,9)
+K_F11 K(KT_FN,10)
+K_F12 K(KT_FN,11)
+K_F13 K(KT_FN,12)
+K_F14 K(KT_FN,13)
+K_F15 K(KT_FN,14)
+K_F16 K(KT_FN,15)
+K_F17 K(KT_FN,16)
+K_F18 K(KT_FN,17)
+K_F19 K(KT_FN,18)
+K_F20 K(KT_FN,19)
+K_FIND K(KT_FN,20)
+K_INSERT K(KT_FN,21)
+K_REMOVE K(KT_FN,22)
+K_SELECT K(KT_FN,23)
+K_PGUP K(KT_FN,24)
+K_PGDN K(KT_FN,25)
+K_MACRO K(KT_FN,26)
+K_HELP K(KT_FN,27)
+K_DO K(KT_FN,28)
+K_PAUSE K(KT_FN,29)
+K_F21 K(KT_FN,30)
+K_F22 K(KT_FN,31)
+K_F23 K(KT_FN,32)
+K_F24 K(KT_FN,33)
+K_F25 K(KT_FN,34)
+K_F26 K(KT_FN,35)
+K_F27 K(KT_FN,36)
+K_F28 K(KT_FN,37)
+K_F29 K(KT_FN,38)
+K_F30 K(KT_FN,39)
+K_F31 K(KT_FN,40)
+K_F32 K(KT_FN,41)
+K_F33 K(KT_FN,42)
+K_F34 K(KT_FN,43)
+K_F35 K(KT_FN,44)
+K_F36 K(KT_FN,45)
+K_F37 K(KT_FN,46)
+K_F38 K(KT_FN,47)
+K_F39 K(KT_FN,48)
+K_F40 K(KT_FN,49)
+K_F41 K(KT_FN,50)
+K_F42 K(KT_FN,51)
+K_F43 K(KT_FN,52)
+K_F44 K(KT_FN,53)
+K_F45 K(KT_FN,54)
+K_F46 K(KT_FN,55)
+K_F47 K(KT_FN,56)
+K_F48 K(KT_FN,57)
+K_F49 K(KT_FN,58)
+K_F50 K(KT_FN,59)
+K_F51 K(KT_FN,60)
+K_F52 K(KT_FN,61)
+K_F53 K(KT_FN,62)
+K_F54 K(KT_FN,63)
+K_F55 K(KT_FN,64)
+K_F56 K(KT_FN,65)
+K_F57 K(KT_FN,66)
+K_F58 K(KT_FN,67)
+K_F59 K(KT_FN,68)
+K_F60 K(KT_FN,69)
+K_F61 K(KT_FN,70)
+K_F62 K(KT_FN,71)
+K_F63 K(KT_FN,72)
+K_F64 K(KT_FN,73)
+K_F65 K(KT_FN,74)
+K_F66 K(KT_FN,75)
+K_F67 K(KT_FN,76)
+K_F68 K(KT_FN,77)
+K_F69 K(KT_FN,78)
+K_F70 K(KT_FN,79)
+K_F71 K(KT_FN,80)
+K_F72 K(KT_FN,81)
+K_F73 K(KT_FN,82)
+K_F74 K(KT_FN,83)
+K_F75 K(KT_FN,84)
+K_F76 K(KT_FN,85)
+K_F77 K(KT_FN,86)
+K_F78 K(KT_FN,87)
+K_F79 K(KT_FN,88)
+K_F80 K(KT_FN,89)
+K_F81 K(KT_FN,90)
+K_F82 K(KT_FN,91)
+K_F83 K(KT_FN,92)
+K_F84 K(KT_FN,93)
+K_F85 K(KT_FN,94)
+K_F86 K(KT_FN,95)
+K_F87 K(KT_FN,96)
+K_F88 K(KT_FN,97)
+K_F89 K(KT_FN,98)
+K_F90 K(KT_FN,99)
+K_F91 K(KT_FN,100)
+K_F92 K(KT_FN,101)
+K_F93 K(KT_FN,102)
+K_F94 K(KT_FN,103)
+K_F95 K(KT_FN,104)
+K_F96 K(KT_FN,105)
+K_F97 K(KT_FN,106)
+K_F98 K(KT_FN,107)
+K_F99 K(KT_FN,108)
+K_F100 K(KT_FN,109)
+K_F101 K(KT_FN,110)
+K_F102 K(KT_FN,111)
+K_F103 K(KT_FN,112)
+K_F104 K(KT_FN,113)
+K_F105 K(KT_FN,114)
+K_F106 K(KT_FN,115)
+K_F107 K(KT_FN,116)
+K_F108 K(KT_FN,117)
+K_F109 K(KT_FN,118)
+K_F110 K(KT_FN,119)
+K_F111 K(KT_FN,120)
+K_F112 K(KT_FN,121)
+K_F113 K(KT_FN,122)
+K_F114 K(KT_FN,123)
+K_F115 K(KT_FN,124)
+K_F116 K(KT_FN,125)
+K_F117 K(KT_FN,126)
+K_F118 K(KT_FN,127)
+K_F119 K(KT_FN,128)
+K_F120 K(KT_FN,129)
+K_F121 K(KT_FN,130)
+K_F122 K(KT_FN,131)
+K_F123 K(KT_FN,132)
+K_F124 K(KT_FN,133)
+K_F125 K(KT_FN,134)
+K_F126 K(KT_FN,135)
+K_F127 K(KT_FN,136)
+K_F128 K(KT_FN,137)
+K_F129 K(KT_FN,138)
+K_F130 K(KT_FN,139)
+K_F131 K(KT_FN,140)
+K_F132 K(KT_FN,141)
+K_F133 K(KT_FN,142)
+K_F134 K(KT_FN,143)
+K_F135 K(KT_FN,144)
+K_F136 K(KT_FN,145)
+K_F137 K(KT_FN,146)
+K_F138 K(KT_FN,147)
+K_F139 K(KT_FN,148)
+K_F140 K(KT_FN,149)
+K_F141 K(KT_FN,150)
+K_F142 K(KT_FN,151)
+K_F143 K(KT_FN,152)
+K_F144 K(KT_FN,153)
+K_F145 K(KT_FN,154)
+K_F146 K(KT_FN,155)
+K_F147 K(KT_FN,156)
+K_F148 K(KT_FN,157)
+K_F149 K(KT_FN,158)
+K_F150 K(KT_FN,159)
+K_F151 K(KT_FN,160)
+K_F152 K(KT_FN,161)
+K_F153 K(KT_FN,162)
+K_F154 K(KT_FN,163)
+K_F155 K(KT_FN,164)
+K_F156 K(KT_FN,165)
+K_F157 K(KT_FN,166)
+K_F158 K(KT_FN,167)
+K_F159 K(KT_FN,168)
+K_F160 K(KT_FN,169)
+K_F161 K(KT_FN,170)
+K_F162 K(KT_FN,171)
+K_F163 K(KT_FN,172)
+K_F164 K(KT_FN,173)
+K_F165 K(KT_FN,174)
+K_F166 K(KT_FN,175)
+K_F167 K(KT_FN,176)
+K_F168 K(KT_FN,177)
+K_F169 K(KT_FN,178)
+K_F170 K(KT_FN,179)
+K_F171 K(KT_FN,180)
+K_F172 K(KT_FN,181)
+K_F173 K(KT_FN,182)
+K_F174 K(KT_FN,183)
+K_F175 K(KT_FN,184)
+K_F176 K(KT_FN,185)
+K_F177 K(KT_FN,186)
+K_F178 K(KT_FN,187)
+K_F179 K(KT_FN,188)
+K_F180 K(KT_FN,189)
+K_F181 K(KT_FN,190)
+K_F182 K(KT_FN,191)
+K_F183 K(KT_FN,192)
+K_F184 K(KT_FN,193)
+K_F185 K(KT_FN,194)
+K_F186 K(KT_FN,195)
+K_F187 K(KT_FN,196)
+K_F188 K(KT_FN,197)
+K_F189 K(KT_FN,198)
+K_F190 K(KT_FN,199)
+K_F191 K(KT_FN,200)
+K_F192 K(KT_FN,201)
+K_F193 K(KT_FN,202)
+K_F194 K(KT_FN,203)
+K_F195 K(KT_FN,204)
+K_F196 K(KT_FN,205)
+K_F197 K(KT_FN,206)
+K_F198 K(KT_FN,207)
+K_F199 K(KT_FN,208)
+K_F200 K(KT_FN,209)
+K_F201 K(KT_FN,210)
+K_F202 K(KT_FN,211)
+K_F203 K(KT_FN,212)
+K_F204 K(KT_FN,213)
+K_F205 K(KT_FN,214)
+K_F206 K(KT_FN,215)
+K_F207 K(KT_FN,216)
+K_F208 K(KT_FN,217)
+K_F209 K(KT_FN,218)
+K_F210 K(KT_FN,219)
+K_F211 K(KT_FN,220)
+K_F212 K(KT_FN,221)
+K_F213 K(KT_FN,222)
+K_F214 K(KT_FN,223)
+K_F215 K(KT_FN,224)
+K_F216 K(KT_FN,225)
+K_F217 K(KT_FN,226)
+K_F218 K(KT_FN,227)
+K_F219 K(KT_FN,228)
+K_F220 K(KT_FN,229)
+K_F221 K(KT_FN,230)
+K_F222 K(KT_FN,231)
+K_F223 K(KT_FN,232)
+K_F224 K(KT_FN,233)
+K_F225 K(KT_FN,234)
+K_F226 K(KT_FN,235)
+K_F227 K(KT_FN,236)
+K_F228 K(KT_FN,237)
+K_F229 K(KT_FN,238)
+K_F230 K(KT_FN,239)
+K_F231 K(KT_FN,240)
+K_F232 K(KT_FN,241)
+K_F233 K(KT_FN,242)
+K_F234 K(KT_FN,243)
+K_F235 K(KT_FN,244)
+K_F236 K(KT_FN,245)
+K_F237 K(KT_FN,246)
+K_F238 K(KT_FN,247)
+K_F239 K(KT_FN,248)
+K_F240 K(KT_FN,249)
+K_F241 K(KT_FN,250)
+K_F242 K(KT_FN,251)
+K_F243 K(KT_FN,252)
+K_F244 K(KT_FN,253)
+K_F245 K(KT_FN,254)
+K_UNDO K(KT_FN,255)
diff --git a/src/xlat/kd_key_lock_keys.in b/src/xlat/kd_key_lock_keys.in
new file mode 100644
index 000000000..b2ec999fc
--- /dev/null
+++ b/src/xlat/kd_key_lock_keys.in
@@ -0,0 +1,10 @@
+#sorted
+K_SHIFTLOCK K(KT_LOCK,KG_SHIFT)
+K_ALTGRLOCK K(KT_LOCK,KG_ALTGR)
+K_CTRLLOCK K(KT_LOCK,KG_CTRL)
+K_ALTLOCK K(KT_LOCK,KG_ALT)
+K_SHIFTLLOCK K(KT_LOCK,KG_SHIFTL)
+K_SHIFTRLOCK K(KT_LOCK,KG_SHIFTR)
+K_CTRLLLOCK K(KT_LOCK,KG_CTRLL)
+K_CTRLRLOCK K(KT_LOCK,KG_CTRLR)
+K_CAPSSHIFTLOCK K(KT_LOCK,KG_CAPSSHIFT)
diff --git a/src/xlat/kd_key_pad_keys.in b/src/xlat/kd_key_pad_keys.in
new file mode 100644
index 000000000..a988997a0
--- /dev/null
+++ b/src/xlat/kd_key_pad_keys.in
@@ -0,0 +1,21 @@
+#sorted
+K_P0 K(KT_PAD,0)
+K_P1 K(KT_PAD,1)
+K_P2 K(KT_PAD,2)
+K_P3 K(KT_PAD,3)
+K_P4 K(KT_PAD,4)
+K_P5 K(KT_PAD,5)
+K_P6 K(KT_PAD,6)
+K_P7 K(KT_PAD,7)
+K_P8 K(KT_PAD,8)
+K_P9 K(KT_PAD,9)
+K_PPLUS K(KT_PAD,10)
+K_PMINUS K(KT_PAD,11)
+K_PSTAR K(KT_PAD,12)
+K_PSLASH K(KT_PAD,13)
+K_PENTER K(KT_PAD,14)
+K_PCOMMA K(KT_PAD,15)
+K_PDOT K(KT_PAD,16)
+K_PPLUSMINUS K(KT_PAD,17)
+K_PPARENL K(KT_PAD,18)
+K_PPARENR K(KT_PAD,19)
diff --git a/src/xlat/kd_key_shift_keys.in b/src/xlat/kd_key_shift_keys.in
new file mode 100644
index 000000000..219907444
--- /dev/null
+++ b/src/xlat/kd_key_shift_keys.in
@@ -0,0 +1,10 @@
+#sorted
+K_SHIFT K(KT_SHIFT,KG_SHIFT)
+K_ALTGR K(KT_SHIFT,KG_ALTGR)
+K_CTRL K(KT_SHIFT,KG_CTRL)
+K_ALT K(KT_SHIFT,KG_ALT)
+K_SHIFTL K(KT_SHIFT,KG_SHIFTL)
+K_SHIFTR K(KT_SHIFT,KG_SHIFTR)
+K_CTRLL K(KT_SHIFT,KG_CTRLL)
+K_CTRLR K(KT_SHIFT,KG_CTRLR)
+K_CAPSSHIFT K(KT_SHIFT,KG_CAPSSHIFT)
diff --git a/src/xlat/kd_key_slock_keys.in b/src/xlat/kd_key_slock_keys.in
new file mode 100644
index 000000000..605f36299
--- /dev/null
+++ b/src/xlat/kd_key_slock_keys.in
@@ -0,0 +1,10 @@
+#sorted
+K_SHIFT_SLOCK K(KT_SLOCK,KG_SHIFT)
+K_ALTGR_SLOCK K(KT_SLOCK,KG_ALTGR)
+K_CTRL_SLOCK K(KT_SLOCK,KG_CTRL)
+K_ALT_SLOCK K(KT_SLOCK,KG_ALT)
+K_SHIFTL_SLOCK K(KT_SLOCK,KG_SHIFTL)
+K_SHIFTR_SLOCK K(KT_SLOCK,KG_SHIFTR)
+K_CTRLL_SLOCK K(KT_SLOCK,KG_CTRLL)
+K_CTRLR_SLOCK K(KT_SLOCK,KG_CTRLR)
+K_CAPSSHIFT_SLOCK K(KT_SLOCK,KG_CAPSSHIFT)
diff --git a/src/xlat/kd_key_spec_keys.in b/src/xlat/kd_key_spec_keys.in
new file mode 100644
index 000000000..d3a17de47
--- /dev/null
+++ b/src/xlat/kd_key_spec_keys.in
@@ -0,0 +1,23 @@
+#sorted
+K_HOLE K(KT_SPEC,0)
+K_ENTER K(KT_SPEC,1)
+K_SH_REGS K(KT_SPEC,2)
+K_SH_MEM K(KT_SPEC,3)
+K_SH_STAT K(KT_SPEC,4)
+K_BREAK K(KT_SPEC,5)
+K_CONS K(KT_SPEC,6)
+K_CAPS K(KT_SPEC,7)
+K_NUM K(KT_SPEC,8)
+K_HOLD K(KT_SPEC,9)
+K_SCROLLFORW K(KT_SPEC,10)
+K_SCROLLBACK K(KT_SPEC,11)
+K_BOOT K(KT_SPEC,12)
+K_CAPSON K(KT_SPEC,13)
+K_COMPOSE K(KT_SPEC,14)
+K_SAK K(KT_SPEC,15)
+K_DECRCONSOLE K(KT_SPEC,16)
+K_INCRCONSOLE K(KT_SPEC,17)
+K_SPAWNCONSOLE K(KT_SPEC,18)
+K_BARENUMLOCK K(KT_SPEC,19)
+K_ALLOCATED K(KT_SPEC,126)
+K_NOSUCHMAP K(KT_SPEC,127)
diff --git a/src/xlat/kd_key_tables.in b/src/xlat/kd_key_tables.in
new file mode 100644
index 000000000..ac22dd7e5
--- /dev/null
+++ b/src/xlat/kd_key_tables.in
@@ -0,0 +1,5 @@
+#value_indexed
+K_NORMTAB 0
+K_SHIFTTAB 1
+K_ALTTAB 2
+K_ALTSHIFTTAB 3
diff --git a/src/xlat/kd_key_types.in b/src/xlat/kd_key_types.in
new file mode 100644
index 000000000..feac2c50f
--- /dev/null
+++ b/src/xlat/kd_key_types.in
@@ -0,0 +1,16 @@
+#value_indexed
+KT_LATIN 0
+KT_FN 1
+KT_SPEC 2
+KT_PAD 3
+KT_DEAD 4
+KT_CONS 5
+KT_CUR 6
+KT_SHIFT 7
+KT_META 8
+KT_ASCII 9
+KT_LOCK 10
+KT_LETTER 11
+KT_SLOCK 12
+KT_DEAD2 13
+KT_BRL 14
diff --git a/src/xlat/kd_keymap_flags.in b/src/xlat/kd_keymap_flags.in
new file mode 100644
index 000000000..5e5ad336f
--- /dev/null
+++ b/src/xlat/kd_keymap_flags.in
@@ -0,0 +1,8 @@
+1<<KG_SHIFT 1<<0
+1<<KG_ALTGR 1<<1
+1<<KG_CTRL 1<<2
+1<<KG_ALT 1<<3
+1<<KG_SHIFTL 1<<4
+1<<KG_SHIFTR 1<<5
+1<<KG_CTRLL 1<<6
+1<<KG_CTRLR 1<<7
diff --git a/src/xlat/kd_led_flags.in b/src/xlat/kd_led_flags.in
new file mode 100644
index 000000000..afefb621a
--- /dev/null
+++ b/src/xlat/kd_led_flags.in
@@ -0,0 +1,3 @@
+LED_SCR 0x1
+LED_NUM 0x2
+LED_CAP 0x4
diff --git a/src/xlat/kd_meta_vals.in b/src/xlat/kd_meta_vals.in
new file mode 100644
index 000000000..b0b43b167
--- /dev/null
+++ b/src/xlat/kd_meta_vals.in
@@ -0,0 +1,2 @@
+K_METABIT 0x3
+K_ESCPREFIX 0x4
diff --git a/src/xlat/kd_modes.in b/src/xlat/kd_modes.in
new file mode 100644
index 000000000..99ffdb867
--- /dev/null
+++ b/src/xlat/kd_modes.in
@@ -0,0 +1,5 @@
+#value_indexed
+KD_TEXT 0x0
+KD_GRAPHICS 0x1
+KD_TEXT0 0x2
+KD_TEXT1 0x3
diff --git a/tests/.gitignore b/tests/.gitignore
index d76512dc8..7d32596fa 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -302,6 +302,18 @@ ioctl_hdio-v-Xabbrev
ioctl_hdio-v-Xraw
ioctl_hdio-v-Xverbose
ioctl_inotify
+ioctl_kd
+ioctl_kd-Xabbrev
+ioctl_kd-Xraw
+ioctl_kd-Xverbose
+ioctl_kd-success
+ioctl_kd-success-Xabbrev
+ioctl_kd-success-Xraw
+ioctl_kd-success-Xverbose
+ioctl_kd-success-s1024
+ioctl_kd-success-s1024-Xabbrev
+ioctl_kd-success-s1024-Xraw
+ioctl_kd-success-s1024-Xverbose
ioctl_kvm_run
ioctl_kvm_run-v
ioctl_kvm_run_auxstr_vcpu
diff --git a/tests/Makefile.am b/tests/Makefile.am
index fe33e180a..cd71b4638 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -192,6 +192,14 @@ check_PROGRAMS = $(PURE_EXECUTABLES) \
ioctl_hdio-success-v-Xabbrev \
ioctl_hdio-success-v-Xraw \
ioctl_hdio-success-v-Xverbose \
+ ioctl_kd-success \
+ ioctl_kd-success-Xabbrev \
+ ioctl_kd-success-Xraw \
+ ioctl_kd-success-Xverbose \
+ ioctl_kd-success-s1024 \
+ ioctl_kd-success-s1024-Xabbrev \
+ ioctl_kd-success-s1024-Xraw \
+ ioctl_kd-success-s1024-Xverbose \
ioctl_loop-nv \
ioctl_loop-v \
ioctl_mtd-success \
diff --git a/tests/gen_tests.in b/tests/gen_tests.in
index 30a520e68..a88af6970 100644
--- a/tests/gen_tests.in
+++ b/tests/gen_tests.in
@@ -296,6 +296,18 @@ ioctl_hdio-v-Xabbrev +ioctl.test -a27 -v -Xabbrev
ioctl_hdio-v-Xraw +ioctl.test -a20 -v -Xraw
ioctl_hdio-v-Xverbose +ioctl.test -a39 -v -Xverbose
ioctl_inotify +ioctl.test
+ioctl_kd +ioctl.test -a20
+ioctl_kd-Xabbrev +ioctl.test -a20 -Xabbrev
+ioctl_kd-Xraw +ioctl.test -a18 -Xraw
+ioctl_kd-Xverbose +ioctl.test -a20 -Xverbose
+ioctl_kd-success +ioctl-success.sh -a20
+ioctl_kd-success-Xabbrev +ioctl-success.sh -a20 -Xabbrev
+ioctl_kd-success-Xraw +ioctl-success.sh -a18 -Xraw
+ioctl_kd-success-Xverbose +ioctl-success.sh -a20 -Xverbose
+ioctl_kd-success-s1024 +ioctl-success.sh -a20 -s1024
+ioctl_kd-success-s1024-Xabbrev +ioctl-success.sh -a20 -s1024 -Xabbrev
+ioctl_kd-success-s1024-Xraw +ioctl-success.sh -a18 -s1024 -Xraw
+ioctl_kd-success-s1024-Xverbose +ioctl-success.sh -a20 -s1024 -Xverbose
ioctl_kvm_run +ioctl.test -a36 -y
ioctl_kvm_run-v +ioctl.test -v -a36 -y
ioctl_kvm_run_auxstr_vcpu +ioctl.test -a36 -y -e kvm=vcpu
diff --git a/tests/ioctl_kd-Xabbrev.c b/tests/ioctl_kd-Xabbrev.c
new file mode 100644
index 000000000..cab5d2820
--- /dev/null
+++ b/tests/ioctl_kd-Xabbrev.c
@@ -0,0 +1 @@
+#include "ioctl_kd.c"
diff --git a/tests/ioctl_kd-Xraw.c b/tests/ioctl_kd-Xraw.c
new file mode 100644
index 000000000..d97346cf4
--- /dev/null
+++ b/tests/ioctl_kd-Xraw.c
@@ -0,0 +1,2 @@
+#define XLAT_RAW 1
+#include "ioctl_kd.c"
diff --git a/tests/ioctl_kd-Xverbose.c b/tests/ioctl_kd-Xverbose.c
new file mode 100644
index 000000000..db171cc7e
--- /dev/null
+++ b/tests/ioctl_kd-Xverbose.c
@@ -0,0 +1,2 @@
+#define XLAT_VERBOSE 1
+#include "ioctl_kd.c"
diff --git a/tests/ioctl_kd-success-Xabbrev.c b/tests/ioctl_kd-success-Xabbrev.c
new file mode 100644
index 000000000..a1fe5d90b
--- /dev/null
+++ b/tests/ioctl_kd-success-Xabbrev.c
@@ -0,0 +1 @@
+#include "ioctl_kd-success.c"
diff --git a/tests/ioctl_kd-success-Xraw.c b/tests/ioctl_kd-success-Xraw.c
new file mode 100644
index 000000000..de7f49365
--- /dev/null
+++ b/tests/ioctl_kd-success-Xraw.c
@@ -0,0 +1,2 @@
+#define XLAT_RAW 1
+#include "ioctl_kd-success.c"
diff --git a/tests/ioctl_kd-success-Xverbose.c b/tests/ioctl_kd-success-Xverbose.c
new file mode 100644
index 000000000..e22aeecca
--- /dev/null
+++ b/tests/ioctl_kd-success-Xverbose.c
@@ -0,0 +1,2 @@
+#define XLAT_VERBOSE 1
+#include "ioctl_kd-success.c"
diff --git a/tests/ioctl_kd-success-s1024-Xabbrev.c b/tests/ioctl_kd-success-s1024-Xabbrev.c
new file mode 100644
index 000000000..a0c9c5cb0
--- /dev/null
+++ b/tests/ioctl_kd-success-s1024-Xabbrev.c
@@ -0,0 +1,2 @@
+#define DEFAULT_STRLEN 1024
+#include "ioctl_kd-success-Xabbrev.c"
diff --git a/tests/ioctl_kd-success-s1024-Xraw.c b/tests/ioctl_kd-success-s1024-Xraw.c
new file mode 100644
index 000000000..e86c67713
--- /dev/null
+++ b/tests/ioctl_kd-success-s1024-Xraw.c
@@ -0,0 +1,2 @@
+#define DEFAULT_STRLEN 1024
+#include "ioctl_kd-success-Xraw.c"
diff --git a/tests/ioctl_kd-success-s1024-Xverbose.c b/tests/ioctl_kd-success-s1024-Xverbose.c
new file mode 100644
index 000000000..4c4e3051a
--- /dev/null
+++ b/tests/ioctl_kd-success-s1024-Xverbose.c
@@ -0,0 +1,2 @@
+#define DEFAULT_STRLEN 1024
+#include "ioctl_kd-success-Xverbose.c"
diff --git a/tests/ioctl_kd-success-s1024.c b/tests/ioctl_kd-success-s1024.c
new file mode 100644
index 000000000..b952eebcf
--- /dev/null
+++ b/tests/ioctl_kd-success-s1024.c
@@ -0,0 +1,2 @@
+#define DEFAULT_STRLEN 1024
+#include "ioctl_kd-success.c"
diff --git a/tests/ioctl_kd-success.c b/tests/ioctl_kd-success.c
new file mode 100644
index 000000000..21dea646b
--- /dev/null
+++ b/tests/ioctl_kd-success.c
@@ -0,0 +1,2 @@
+#define RETVAL_INJECTED 1
+#include "ioctl_kd.c"
diff --git a/tests/ioctl_kd.c b/tests/ioctl_kd.c
new file mode 100644
index 000000000..eb4e50a52
--- /dev/null
+++ b/tests/ioctl_kd.c
@@ -0,0 +1,1733 @@
+/*
+ * This file is part of ioctl_kd strace test.
+ *
+ * Copyright (c) 2019-2021 Eugene Syromyatnikov <evgsyr@gmail.com>
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "tests.h"
+
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "scno.h"
+
+#include <linux/ioctl.h>
+#include <linux/kd.h>
+#include <linux/keyboard.h>
+
+#ifndef RETVAL_INJECTED
+# define RETVAL_INJECTED 0
+#endif
+
+#if RETVAL_INJECTED
+# define RETVAL "42 (INJECTED)\n"
+#else
+# define RETVAL "-1 EBADF (%m)\n"
+#endif
+
+#define ARG_XLAT_KNOWN(val_, str_) val_, XLAT_KNOWN(val_, str_)
+#define ARG_XLAT_UNKNOWN(val_, str_) val_, XLAT_UNKNOWN(val_, str_)
+
+struct arg_val {
+ kernel_ulong_t val;
+ const char *str;
+};
+
+static long
+sys_ioctl(kernel_long_t fd, kernel_ulong_t cmd, kernel_ulong_t arg)
+{
+ return syscall(__NR_ioctl, fd, cmd, arg);
+}
+
+static void
+check_null_invalid(unsigned int c, const char *s)
+{
+ static char *p;
+
+ if (!p)
+ p = tail_alloc(1);
+
+ sys_ioctl(-1, c, 0);
+ printf("ioctl(-1, " XLAT_FMT ", NULL) = " RETVAL, XLAT_SEL(c, s));
+
+ if (F8ILL_KULONG_SUPPORTED) {
+ sys_ioctl(-1, c, F8ILL_KULONG_MASK);
+ printf("ioctl(-1, " XLAT_FMT ", NULL) = " RETVAL,
+ XLAT_SEL(c, s));
+ }
+
+ sys_ioctl(-1, c, (uintptr_t) p + 1);
+ printf("ioctl(-1, " XLAT_FMT ", %p) = " RETVAL, XLAT_SEL(c, s), p + 1);
+}
+
+/* GIO_SCRNMAP, PIO_SCRNMAP */
+static void
+check_scrnmap(unsigned int c, const char *s)
+{
+ char *scrnmap = tail_alloc(E_TABSZ);
+
+ int saved_errno;
+ long rc;
+
+ fill_memory_ex(scrnmap, E_TABSZ, 0, 0xff);
+
+ check_null_invalid(c, s);
+
+ sys_ioctl(-1, c, (uintptr_t) scrnmap + E_TABSZ - 31);
+ printf("ioctl(-1, " XLAT_FMT ", %p) = " RETVAL,
+ XLAT_SEL(c, s), scrnmap + E_TABSZ - 31);
+
+ sys_ioctl(-1, c, (uintptr_t) scrnmap + E_TABSZ - 32);
+ printf("ioctl(-1, " XLAT_FMT ", %p) = " RETVAL,
+ XLAT_SEL(c, s), scrnmap + E_TABSZ - 32);
+
+ rc = sys_ioctl(-1, c, (uintptr_t) scrnmap + E_TABSZ - 33);
+ saved_errno = errno;
+ printf("ioctl(-1, " XLAT_FMT ", ", XLAT_SEL(c, s));
+ if ((rc >= 0 || c == PIO_SCRNMAP) && (DEFAULT_STRLEN <= 32)) {
+ print_quoted_hex(scrnmap + E_TABSZ - 33, 32);
+ printf("...");
+ } else {
+ printf("%p", scrnmap + E_TABSZ - 33);
+ }
+ errno = saved_errno;
+ printf(") = " RETVAL);
+
+ rc = sys_ioctl(-1, c, (uintptr_t) scrnmap);
+ saved_errno = errno;
+ printf("ioctl(-1, " XLAT_FMT ", ", XLAT_SEL(c, s));
+ if (rc >= 0 || c == PIO_SCRNMAP) {
+ print_quoted_hex(scrnmap, MIN(E_TABSZ, DEFAULT_STRLEN));
+ if (DEFAULT_STRLEN < E_TABSZ)
+ printf("...");
+ } else {
+ printf("%p", scrnmap);
+ }
+ errno = saved_errno;
+ printf(") = " RETVAL);
+}
+
+/* KDGKBENT, KDSKBENT */
+static void
+check_kbdent(unsigned int c, const char *s)
+{
+ static const struct arg_val kbtbl_vecs[] = {
+ { ARG_XLAT_KNOWN(0, "K_NORMTAB") },
+ { ARG_XLAT_KNOWN(0x1, "K_SHIFTTAB") },
+ { ARG_XLAT_KNOWN(0x3, "K_ALTSHIFTTAB") },
+ { ARG_XLAT_KNOWN(0x4, "1<<KG_CTRL") },
+ { ARG_XLAT_KNOWN(0xff,
+ "1<<KG_SHIFT|1<<KG_ALTGR|1<<KG_CTRL"
+ "|1<<KG_ALT|1<<KG_SHIFTL|1<<KG_SHIFTR"
+ "|1<<KG_CTRLL|1<<KG_CTRLR") },
+ };
+
+ static const struct arg_val kbval_vecs[] = {
+ { ARG_STR(0) NRAW(" /* K(KT_LATIN, '\\x00') */") },
+ { ARG_STR(0x10) NRAW(" /* K(KT_LATIN, '\\x10') */") },
+ { ARG_STR(0x20) NRAW(" /* K(KT_LATIN, ' ') */") },
+ { ARG_STR(0x7e) NRAW(" /* K(KT_LATIN, '~') */") },
+ { ARG_STR(0x7f) NRAW(" /* K(KT_LATIN, '\\x7f') */") },
+
+ { ARG_STR(0x100) NRAW(" /* K_F1 */") },
+ { ARG_STR(0x11d) NRAW(" /* K_PAUSE */") },
+ { ARG_STR(0x1ff) NRAW(" /* K_UNDO */") },
+
+ { ARG_STR(0x200) NRAW(" /* K_HOLE */") },
+ { ARG_STR(0x213) NRAW(" /* K_BARENUMLOCK */") },
+ { ARG_STR(0x214) NRAW(" /* K(KT_SPEC, 0x14) */") },
+ { ARG_STR(0x27d) NRAW(" /* K(KT_SPEC, 0x7d) */") },
+ { ARG_STR(0x27e) NRAW(" /* K_ALLOCATED */") },
+ { ARG_STR(0x27f) NRAW(" /* K_NOSUCHMAP */") },
+ { ARG_STR(0x280) NRAW(" /* K(KT_SPEC, 0x80) */") },
+ { ARG_STR(0x2ff) NRAW(" /* K(KT_SPEC, 0xff) */") },
+
+ { ARG_STR(0x300) NRAW(" /* K_P0 */") },
+ { ARG_STR(0x313) NRAW(" /* K_PPARENR */") },
+ { ARG_STR(0x314) NRAW(" /* K(KT_PAD, 0x14) */") },
+ { ARG_STR(0x37f) NRAW(" /* K(KT_PAD, 0x7f) */") },
+ { ARG_STR(0x3ff) NRAW(" /* K(KT_PAD, 0xff) */") },
+
+ { ARG_STR(0x400) NRAW(" /* K_DGRAVE */") },
+ { ARG_STR(0x41a) NRAW(" /* K_DGREEK */") },
+ { ARG_STR(0x41b) NRAW(" /* K(KT_DEAD, 0x1b) */") },
+ { ARG_STR(0x47f) NRAW(" /* K(KT_DEAD, 0x7f) */") },
+ { ARG_STR(0x4ff) NRAW(" /* K(KT_DEAD, 0xff) */") },
+
+ { ARG_STR(0x500) NRAW(" /* K(KT_CONS, 0) */") },
+ { ARG_STR(0x540) NRAW(" /* K(KT_CONS, 0x40) */") },
+ { ARG_STR(0x5ff) NRAW(" /* K(KT_CONS, 0xff) */") },
+
+ { ARG_STR(0x600) NRAW(" /* K_DOWN */") },
+ { ARG_STR(0x603) NRAW(" /* K_UP */") },
+ { ARG_STR(0x604) NRAW(" /* K(KT_CUR, 0x4) */") },
+ { ARG_STR(0x680) NRAW(" /* K(KT_CUR, 0x80) */") },
+ { ARG_STR(0x6ff) NRAW(" /* K(KT_CUR, 0xff) */") },
+
+ { ARG_STR(0x700) NRAW(" /* K_SHIFT */") },
+ { ARG_STR(0x708) NRAW(" /* K_CAPSSHIFT */") },
+ { ARG_STR(0x709) NRAW(" /* K(KT_SHIFT, 0x9) */") },
+ { ARG_STR(0x7ff) NRAW(" /* K(KT_SHIFT, 0xff) */") },
+
+ { ARG_STR(0x800) NRAW(" /* K(KT_META, '\\x00') */") },
+ { ARG_STR(0x841) NRAW(" /* K(KT_META, 'A') */") },
+ { ARG_STR(0x8ff) NRAW(" /* K(KT_META, '\\xff') */") },
+
+ { ARG_STR(0x900) NRAW(" /* K_ASC0 */") },
+ { ARG_STR(0x909) NRAW(" /* K_ASC9 */") },
+ { ARG_STR(0x90a) NRAW(" /* K_HEX0 */") },
+ { ARG_STR(0x919) NRAW(" /* K_HEXf */") },
+ { ARG_STR(0x91a) NRAW(" /* K(KT_ASCII, 0x1a) */") },
+ { ARG_STR(0x9ff) NRAW(" /* K(KT_ASCII, 0xff) */") },
+
+ { ARG_STR(0xa00) NRAW(" /* K_SHIFTLOCK */") },
+ { ARG_STR(0xa08) NRAW(" /* K_CAPSSHIFTLOCK */") },
+ { ARG_STR(0xa09) NRAW(" /* K(KT_LOCK, 0x9) */") },
+ { ARG_STR(0xaff) NRAW(" /* K(KT_LOCK, 0xff) */") },
+
+ { ARG_STR(0xb00) NRAW(" /* K(KT_LETTER, '\\x00') */") },
+ { ARG_STR(0xb40) NRAW(" /* K(KT_LETTER, '@') */") },
+ { ARG_STR(0xb7f) NRAW(" /* K(KT_LETTER, '\\x7f') */") },
+ { ARG_STR(0xbff) NRAW(" /* K(KT_LETTER, '\\xff') */") },
+
+ { ARG_STR(0xc00) NRAW(" /* K_SHIFT_SLOCK */") },
+ { ARG_STR(0xc08) NRAW(" /* K_CAPSSHIFT_SLOCK */") },
+ { ARG_STR(0xc09) NRAW(" /* K(KT_SLOCK, 0x9) */") },
+ { ARG_STR(0xcff) NRAW(" /* K(KT_SLOCK, 0xff) */") },
+
+ { ARG_STR(0xd00) NRAW(" /* K(KT_DEAD2, '\\x00') */") },
+ { ARG_STR(0xd13) NRAW(" /* K(KT_DEAD2, '\\x13') */") },
+ { ARG_STR(0xd5c) NRAW(" /* K(KT_DEAD2, '\\\\') */") },
+ { ARG_STR(0xdff) NRAW(" /* K(KT_DEAD2, '\\xff') */") },
+
+ { ARG_STR(0xe00) NRAW(" /* K_BRL_BLANK */") },
+ { ARG_STR(0xe0a) NRAW(" /* K_BRL_DOT10 */") },
+ { ARG_STR(0xe0b) NRAW(" /* K(KT_BRL, 0xb) */") },
+ { ARG_STR(0xeff) NRAW(" /* K(KT_BRL, 0xff) */") },
+
+ { ARG_STR(0xf00) NRAW(" /* K(0xf, 0) */") },
+ { ARG_STR(0xfed) NRAW(" /* K(0xf, 0xed) */") },
+ { ARG_STR(0xf00d) NRAW(" /* K(0xf0, 0xd) */") },
+ };
+
+ struct kbentry *kbe = tail_alloc(sizeof(*kbe));
+
+ int saved_errno;
+ long rc;
+
+ check_null_invalid(c, s);
+
+ kbe->kb_value = 0xa8a8;
+ sys_ioctl(-1, c, (uintptr_t) kbe + 2);
+ printf("ioctl(-1, " XLAT_FMT ", {kb_table=%s, kb_index=168%s}"
+ ") = " RETVAL,
+ XLAT_SEL(c, s), XLAT_STR(1<<KG_ALT|1<<KG_SHIFTR|1<<KG_CTRLR),
+ RETVAL_INJECTED || c == KDSKBENT ? ", kb_value=???" : ""
+ );
+
+ for (size_t i = 0;
+ i < MAX(ARRAY_SIZE(kbtbl_vecs), ARRAY_SIZE(kbval_vecs)); i++) {
+ kbe->kb_table = kbtbl_vecs[i % ARRAY_SIZE(kbtbl_vecs)].val;
+ kbe->kb_index = i * 3141;
+ kbe->kb_value = kbval_vecs[i % ARRAY_SIZE(kbval_vecs)].val;
+
+ rc = sys_ioctl(-1, c, (uintptr_t) kbe);
+ saved_errno = errno;
+ printf("ioctl(-1, " XLAT_FMT ", {kb_table=%s, kb_index=%u",
+ XLAT_SEL(c, s),
+ kbtbl_vecs[i % ARRAY_SIZE(kbtbl_vecs)].str,
+ kbe->kb_index);
+ if (rc >= 0 || c == KDSKBENT) {
+ printf(", kb_value=%s",
+ kbval_vecs[i % ARRAY_SIZE(kbval_vecs)].str);
+ }
+ errno = saved_errno;
+ printf("}) = " RETVAL);
+ }
+}
+
+/* KDGKBSENT, KDSKBSENT */
+static void
+check_kbdsent(unsigned int c, const char *s)
+{
+ static struct arg_val kbse_offsets[] = {
+ { sizeof(struct kbsentry) - 1, "KVAL(K_F2)" },
+ { sizeof(struct kbsentry) - 2, "KVAL(K_F1)" },
+ { sizeof(struct kbsentry) - 34, "KVAL(K_F214)" },
+ { sizeof(struct kbsentry) - 35, "KVAL(K_F213)" },
+ { 1, "KVAL(K_F1)" },
+ { 0, "KVAL(K_F245)" },
+ };
+
+ static const struct arg_val kbfn_vecs[] = {
+ { ARG_XLAT_KNOWN(0, "KVAL(K_F1)") },
+ { ARG_XLAT_KNOWN(0x10, "KVAL(K_F17)") },
+ { ARG_XLAT_KNOWN(0x7f, "KVAL(K_F118)") },
+ { ARG_XLAT_KNOWN(0xff, "KVAL(K_UNDO)") },
+ };
+
+ struct kbsentry *kbse = tail_alloc(sizeof(*kbse));
+
+ int saved_errno;
+
+ fill_memory_ex(kbse->kb_string, sizeof(kbse->kb_string), 0, 0xff);
+ kbse->kb_func = 0xfe;
+
+ check_null_invalid(c, s);
+
+ for (size_t i = 0; i < ARRAY_SIZE(kbse_offsets); i++) {
+ sys_ioctl(-1, c,
+ (uintptr_t) kbse + kbse_offsets[i].val);
+ saved_errno = errno;
+ printf("ioctl(-1, " XLAT_FMT ", {kb_func=%s",
+ XLAT_SEL(c, s),
+ sprintxlat(kbse_offsets[i].str,
+ (kbse_offsets[i].val + 254) % 0xff, NULL));
+
+ if (RETVAL_INJECTED || c == KDSKBSENT) {
+ printf(", kb_string=");
+ if (kbse_offsets[i].val < 255 * 2) {
+ print_quoted_stringn(
+ (char *) kbse->kb_string +
+ kbse_offsets[i].val,
+ MIN(DEFAULT_STRLEN,
+ sizeof(kbse->kb_string)));
+ } else {
+ printf("???");
+ }
+ }
+
+ errno = saved_errno;
+ printf("}) = " RETVAL);
+ }
+
+ fill_memory_ex(kbse->kb_string, sizeof(kbse->kb_string), 0x80, 0x7f);
+ kbse->kb_func = KVAL(K_PGDN);
+
+ sys_ioctl(-1, c, (uintptr_t) kbse);
+ saved_errno = errno;
+ printf("ioctl(-1, " XLAT_FMT ", {kb_func="
+ XLAT_KNOWN(0x19, "KVAL(K_PGDN)"),
+ XLAT_SEL(c, s));
+
+ if (RETVAL_INJECTED || c == KDSKBSENT) {
+ printf(", kb_string=");
+ print_quoted_stringn((char *) kbse->kb_string,
+ MIN(DEFAULT_STRLEN,
+ sizeof(kbse->kb_string)));
+ }
+
+ errno = saved_errno;
+ printf("}) = " RETVAL);
+
+ for (size_t i = 0; i < ARRAY_SIZE(kbfn_vecs); i++) {
+ kbse->kb_func = kbfn_vecs[i].val;
+ fill_memory_ex(kbse->kb_string, sizeof(kbse->kb_string),
+ i * 357 + 42, i * 257 + 13);
+
+ sys_ioctl(-1, c, (uintptr_t) kbse);
+ saved_errno = errno;
+ printf("ioctl(-1, " XLAT_FMT ", {kb_func=%s",
+ XLAT_SEL(c, s),
+ kbfn_vecs[i].str);
+
+ if (RETVAL_INJECTED || c == KDSKBSENT) {
+ printf(", kb_string=");
+ print_quoted_stringn((char *) kbse->kb_string,
+ MIN(DEFAULT_STRLEN,
+ sizeof(kbse->kb_string)));
+ }
+
+ errno = saved_errno;
+ printf("}) = " RETVAL);
+ }
+}
+
+/* KDGKBDIACR, KDSKBDIACR */
+static void
+check_diacr(unsigned int c, const char *s)
+{
+ static struct arg_val diac_vecs[] = {
+ { 0, "\\x00" },
+ { '\n', "\\n" },
+ { ' ', " " },
+ { 'a', "a" },
+ { '~', "~" },
+ { '\'', "\\'" },
+ { '\\', "\\\\" },
+ { '"', "\"" },
+ { '`', "`" },
+ { 0x7f, "\\x7f" },
+ { 0xff, "\\xff" },
+ };
+
+ struct kbdiacrs *diacrs0 = tail_alloc(sizeof(diacrs0->kb_cnt));
+ struct kbdiacrs *diacrs1 = tail_alloc(sizeof(diacrs1->kb_cnt) +
+ 4 * sizeof(struct kbdiacr));
+ struct kbdiacrs *diacrs2 = tail_alloc(sizeof(*diacrs2));
+
+ int saved_errno;
+
+ check_null_invalid(c, s);
+
+ for (size_t i = 0; i < 2; i++) {
+ diacrs0->kb_cnt = i;
+ sys_ioctl(-1, c, (uintptr_t) diacrs0);
+ saved_errno = errno;
+ printf("ioctl(-1, " XLAT_FMT ", ", XLAT_SEL(c, s));
+ if (RETVAL_INJECTED || c == KDSKBDIACR) {
+ printf("{kb_cnt=%zu, kbdiacr=", i);
+ if (i)
+ printf("%p}", diacrs0->kbdiacr);
+ else
+ printf("[]}");
+ } else {
+ printf("%p", diacrs0);
+ }
+ errno = saved_errno;
+ printf(") = " RETVAL);
+ }
+
+ fill_memory_ex(diacrs1->kbdiacr, 4 * sizeof(struct kbdiacr), 40, 44);
+ for (size_t i = 0; i < 7; i++) {
+ diacrs1->kb_cnt = i;
+ sys_ioctl(-1, c, (uintptr_t) diacrs1);
+ saved_errno = errno;
+ printf("ioctl(-1, " XLAT_FMT ", ", XLAT_SEL(c, s));
+ if (RETVAL_INJECTED || c == KDSKBDIACR) {
+ printf("{kb_cnt=%zu, kbdiacr=[", i);
+ for (size_t j = 0; j < MIN(i, 4); j++)
+ printf("%s{diacr='%c', base='%c', result='%c'}",
+ j ? ", " : "", (int) (40 + j * 3),
+ (int) (41 + j * 3), (int) (42 + j * 3));
+
+ if (i > 4)
+ printf(", ... /* %p */", diacrs1->kbdiacr + 4);
+ printf("]}");
+ } else {
+ printf("%p", diacrs1);
+ }
+ errno = saved_errno;
+ printf(") = " RETVAL);
+ }
+
+ fill_memory_ex(diacrs2->kbdiacr, sizeof(diacrs2->kbdiacr), 40, 52);
+
+ for (size_t i = ARRAY_SIZE(diacrs2->kbdiacr) - 1;
+ i < ARRAY_SIZE(diacrs2->kbdiacr) + 3; i++) {
+ diacrs2->kb_cnt = i;
+ sys_ioctl(-1, c, (uintptr_t) diacrs2);
+ printf("ioctl(-1, " XLAT_FMT ", ", XLAT_SEL(c, s));
+ saved_errno = errno;
+ if (RETVAL_INJECTED || c == KDSKBDIACR) {
+ printf("{kb_cnt=%zu, kbdiacr=[", i);
+ for (size_t j = 0;
+ j < MIN(i, MIN(DEFAULT_STRLEN,
+ ARRAY_SIZE(diacrs2->kbdiacr))); j++)
+ printf("%s{diacr='%c', base='%c', result='%c'}",
+ j ? ", " : "",
+ (int) (40 + (j * 3 + 0) % 52),
+ (int) (40 + (j * 3 + 1) % 52),
+ (int) (40 + (j * 3 + 2) % 52));
+
+ if (i > MIN(DEFAULT_STRLEN,
+ ARRAY_SIZE(diacrs2->kbdiacr)))
+ printf(", ...");
+ printf("]}");
+ } else {
+ printf("%p", diacrs2);
+ }
+ errno = saved_errno;
+ printf(") = " RETVAL);
+ }
+
+ for (size_t i = 0; i< ARRAY_SIZE(diac_vecs); i++) {
+ diacrs2->kbdiacr[i].diacr = diac_vecs[i].val;
+ diacrs2->kbdiacr[i].base = diac_vecs[i].val;
+ diacrs2->kbdiacr[i].result = diac_vecs[i].val;
+ }
+ diacrs2->kb_cnt = ARRAY_SIZE(diac_vecs);
+
+ sys_ioctl(-1, c, (uintptr_t) diacrs2);
+ printf("ioctl(-1, " XLAT_FMT ", ", XLAT_SEL(c, s));
+ saved_errno = errno;
+ if (RETVAL_INJECTED || c == KDSKBDIACR) {
+ printf("{kb_cnt=%zu, kbdiacr=[", ARRAY_SIZE(diac_vecs));
+ for (size_t i = 0; i < ARRAY_SIZE(diac_vecs); i++)
+ printf("%1$s{diacr='%2$s', base='%2$s', result='%2$s'}",
+ i ? ", " : "", diac_vecs[i].str);
+ printf("]}");
+ } else {
+ printf("%p", diacrs2);
+ }
+ errno = saved_errno;
+ printf(") = " RETVAL);
+}
+
+/* KDGETKEYCODE, KDSETKEYCODE */
+static void
+check_xetkeycode(unsigned int c, const char *s)
+{
+ static const struct kbkeycode args[] = {
+ { 0, 0 },
+ { 0, 0xdeadface },
+ { 0xfacefeed, 0 },
+ { 0xdecaffed, 0xdadfaced },
+ };
+ struct kbkeycode *tail_arg = tail_alloc(sizeof(args[0]));
+
+ check_null_invalid(c, s);
+
+ sys_ioctl(-1, c, (uintptr_t) tail_arg + 4);
+ printf("ioctl(-1, " XLAT_FMT ", %p) = " RETVAL,
+ XLAT_SEL(c, s), (char *) tail_arg + 4);
+
+ for (size_t i = 0; i < ARRAY_SIZE(args); i++) {
+ memcpy(tail_arg, args + i, sizeof(args[i]));
+
+ sys_ioctl(-1, c, (uintptr_t) tail_arg);
+ printf("ioctl(-1, " XLAT_FMT ", {scancode=%#x, keycode=%#x",
+ XLAT_SEL(c, s), args[i].scancode, args[i].keycode);
+ if ((c == KDGETKEYCODE) && RETVAL_INJECTED)
+ printf(" => %#x", args[i].keycode);
+ printf("}) = " RETVAL);
+ }
+}
+
+/* KDKBDREP */
+static void
+check_kbdrep(unsigned int c, const char *s)
+{
+ static const struct kbd_repeat args[] = {
+ { -1, -1 },
+ { -1234567890, 0 },
+ { 0, -2134567890 },
+ { 314159265, 271828182 },
+ };
+ struct kbd_repeat *tail_arg = tail_alloc(sizeof(args[0]));
+
+ check_null_invalid(c, s);
+
+ sys_ioctl(-1, c, (uintptr_t) tail_arg + 4);
+ printf("ioctl(-1, " XLAT_FMT ", %p) = " RETVAL,
+ XLAT_SEL(c, s), (char *) tail_arg + 4);
+
+ for (size_t i = 0; i < ARRAY_SIZE(args); i++) {
+ memcpy(tail_arg, args + i, sizeof(args[i]));
+
+ sys_ioctl(-1, c, (uintptr_t) tail_arg);
+ printf("ioctl(-1, " XLAT_FMT, XLAT_SEL(c, s));
+ for (size_t j = 0; j < 1 + RETVAL_INJECTED; j++) {
+ printf("%s {delay=%d, period=%d}",
+ j ? " =>" : ",", args[i].delay, args[i].period);
+ }
+ printf(") = " RETVAL);
+ }
+}
+
+/* GIO_FONT, PIO_FONT */
+static void
+check_font(unsigned int c, const char *s)
+{
+ char *data = tail_alloc(8192);
+ char *data_end = data + 8192;
+
+ fill_memory(data, 8192);
+
+ check_null_invalid(c, s);
+
+ sys_ioctl(-1, c, (uintptr_t) data_end - 31);
+ printf("ioctl(-1, " XLAT_FMT ", %p) = " RETVAL,
+ XLAT_SEL(c, s), data_end - 31);
+
+ sys_ioctl(-1, c, (uintptr_t) data_end - 32);
+ printf("ioctl(-1, " XLAT_FMT ", %p) = " RETVAL,
+ XLAT_SEL(c, s), data_end - 32);
+
+ bool ok = (DEFAULT_STRLEN == 32)
+ && ((c != GIO_FONT) || RETVAL_INJECTED);
+ sys_ioctl(-1, c, (uintptr_t) data_end - 33);
+ printf("ioctl(-1, " XLAT_FMT ", %s", XLAT_SEL(c, s), ok ? "\"" : "");
+ if (ok) {
+ for (size_t i = 8192 - 33; i < 8192 - 1; i++)
+ printf("\\x%hhx", (unsigned char) ( 0x80 + i % 0x80));
+ } else {
+ printf("%p", data_end - 33);
+ }
+ printf("%s) = " RETVAL, ok ? "\"..." : "");
+
+ ok = (c != GIO_FONT) || RETVAL_INJECTED;
+ sys_ioctl(-1, c, (uintptr_t) data_end - 1025);
+ printf("ioctl(-1, " XLAT_FMT ", %s", XLAT_SEL(c, s), ok ? "\"" : "");
+ if (ok) {
+ for (size_t i = 8192 - 1025; i < 8192 - 1025 + DEFAULT_STRLEN;
+ i++)
+ printf("\\x%hhx", (unsigned char) (0x80 + i % 0x80));
+ } else {
+ printf("%p", data_end - 1025);
+ }
+ printf("%s) = " RETVAL, ok ? "\"..." : "");
+
+ sys_ioctl(-1, c, (uintptr_t) data);
+ printf("ioctl(-1, " XLAT_FMT ", %s", XLAT_SEL(c, s), ok ? "\"" : "");
+ if (ok) {
+ for (size_t i = 0; i < DEFAULT_STRLEN; i++)
+ printf("\\x%hhx", (unsigned char) (0x80 + i % 0x80));
+ } else {
+ printf("%p", data);
+ }
+ printf("%s) = " RETVAL, ok ? "\"..." : "");
+}
+
+/* GIO_UNIMAP, PIO_UNIMAP */
+static void
+check_unimap(unsigned int c, const char *s)
+{
+ struct unimapdesc *umd = tail_alloc(sizeof(*umd));
+ struct unipair *ups = tail_alloc(33 * sizeof(*ups));
+
+ fill_memory16(ups, 33 * sizeof(*ups));
+ ups[0].unicode = 0;
+ ups[0].fontpos = 0;
+
+ check_null_invalid(c, s);
+
+ umd->entry_ct = 0xdead;
+ umd->entries = NULL;
+ sys_ioctl(-1, c, (uintptr_t) umd);
+ printf("ioctl(-1, " XLAT_FMT ", {entry_ct=57005%s, entries=NULL}) = "
+ RETVAL, XLAT_SEL(c, s), c == GIO_UNIMAP ? " => 57005" : "");
+
+ umd->entry_ct = 0;
+ umd->entries = ups + 33;
+ sys_ioctl(-1, c, (uintptr_t) umd);
+ printf("ioctl(-1, " XLAT_FMT ", {entry_ct=0%s, entries=",
+ XLAT_SEL(c, s), c == GIO_UNIMAP ? " => 0" : "");
+ if (c == GIO_UNIMAP && !RETVAL_INJECTED)
+ printf("%p", ups + 33);
+ else
+ printf("[]");
+ printf("}) = " RETVAL);
+
+ umd->entry_ct = 1;
+ sys_ioctl(-1, c, (uintptr_t) umd);
+ printf("ioctl(-1, " XLAT_FMT ", {entry_ct=1%s, entries=%p}) = " RETVAL,
+ XLAT_SEL(c, s), c == GIO_UNIMAP ? " => 1" : "", ups + 33);
+
+ for (unsigned int i = 0; i < 6; i++) {
+ umd->entry_ct = 31 + (i + 1) / 2;
+ umd->entries = ups + 2 - i / 2;
+ sys_ioctl(-1, c, (uintptr_t) umd);
+ printf("ioctl(-1, " XLAT_FMT ", {entry_ct=%u",
+ XLAT_SEL(c, s), 31 + (i + 1) / 2);
+
+ if (c == GIO_UNIMAP) {
+ printf(" => %u", 31 + (i + 1) / 2);
+#if !RETVAL_INJECTED
+ printf(", entries=%p}) = " RETVAL, ups + 2 - i / 2);
+ continue;
+#endif
+ }
+
+ printf(", entries=[%s", i > 3 ? "{unicode=0, fontpos=0}" : "");
+
+ for (unsigned int j = 0; j < 31
+#if DEFAULT_STRLEN > 32
+ + MIN(i / 2, 1)
+#else
+ + ((i / 2) == 1)
+#endif
+ ; j++) {
+ printf("%s{unicode=%#x, fontpos=%#x}",
+ j == 0 && i < 4 ? "" : ", ",
+ 0x80c4 + 2 * (j - MIN(i / 2, 1)),
+ 0x80c5 + 2 * (j - MIN(i / 2, 1)));
+ }
+ if (i == 1 || i == 3 || ((DEFAULT_STRLEN > 32) && (i == 5)))
+ printf(", ... /* %p */", ups + 33);
+#if DEFAULT_STRLEN == 32
+ if (i > 3)
+ printf(", ...");
+#endif
+ printf("]}) = " RETVAL);
+ }
+}
+
+/* GIO_UNISCRNMAP, PIO_UNISCRNMAP */
+static void
+check_uniscrnmap(unsigned int c, const char *s)
+{
+ uint16_t *map = tail_alloc(256 * sizeof(*map));
+ for (unsigned int i = 0; i < 256; i++)
+ map[i] = 0xeff1 + 32 * (i % 112) - i / 8;
+
+ check_null_invalid(c, s);
+
+ for (unsigned int i = 0; i < 3; i++) {
+ sys_ioctl(-1, c, (uintptr_t) (map + 224 - 112 * i));
+ printf("ioctl(-1, " XLAT_FMT ", ", XLAT_SEL(c, s));
+
+ if (c == GIO_UNISCRNMAP && !RETVAL_INJECTED) {
+ printf("%p) = " RETVAL, map + 224 - 112 * i);
+ continue;
+ }
+
+ for (size_t j = 0;
+ j < MIN(32 + 112 * i, DEFAULT_STRLEN); j++) {
+ uint16_t v = 0xefd5 + 32 * (j % 112) - j / 8 + i * 14;
+ if ((j % 112) < (2 - (i + 1 - j / 112) / 2)
+ || (j % 112) > (17 - (i + 1 - j / 112) / 2)) {
+ printf("%s%#hx", j ? ", " : "[", v);
+ } else {
+ printf(", "
+ XLAT_KNOWN_FMT("%#hx",
+ "UNI_DIRECT_BASE+%#hx"),
+ XLAT_SEL(v, (uint16_t) (v - 0xf000)));
+ }
+ }
+
+ if (DEFAULT_STRLEN == 32 || i < 2) {
+ printf(", ...");
+ if (DEFAULT_STRLEN >= 32 + 112 * i)
+ printf(" /* %p */", map + 256);
+ }
+
+ printf("]) = " RETVAL);
+ }
+}
+
+/* GIO_FONTX, PIO_FONTX */
+static void
+check_fontx(unsigned int c, const char *s)
+{
+ static const short cnts[] = { 1, 32, 256 };
+ struct consolefontdesc *cfd = tail_alloc(sizeof(*cfd));
+ char *data = tail_alloc(2048);
+ char *data_end = data + 2048;
+
+ fill_memory_ex(data, 2048, 0xf0, 255);
+
+ check_null_invalid(c, s);
+
+ cfd->charcount = 0;
+ cfd->charheight = 0xdead;
+ cfd->chardata = NULL;
+ sys_ioctl(-1, c, (uintptr_t) cfd);
+ printf("ioctl(-1, " XLAT_FMT
+ ", {charcount=0, charheight=57005, chardata=NULL}%s) = " RETVAL,
+ XLAT_SEL(c, s), RETVAL_INJECTED && (c == GIO_FONTX)
+ ? " => {charcount=0, charheight=57005, chardata=NULL}" : "");
+
+ cfd->chardata = data_end;
+ sys_ioctl(-1, c, (uintptr_t) cfd);
+ printf("ioctl(-1, " XLAT_FMT
+ ", {charcount=0, charheight=57005, chardata=%p}",
+ XLAT_SEL(c, s), data_end);
+#if RETVAL_INJECTED
+ if (c == GIO_FONTX)
+ printf(" => {charcount=0, charheight=57005, chardata=\"\"}");
+#endif
+ printf(") = " RETVAL);
+
+ cfd->chardata = data;
+ sys_ioctl(-1, c, (uintptr_t) cfd);
+ printf("ioctl(-1, " XLAT_FMT
+ ", {charcount=0, charheight=57005, chardata=%p}",
+ XLAT_SEL(c, s), data);
+#if RETVAL_INJECTED
+ if (c == GIO_FONTX)
+ printf(" => {charcount=0, charheight=57005, chardata=\"\"}");
+#endif
+ printf(") = " RETVAL);
+
+ for (size_t i = 0; i < ARRAY_SIZE(cnts); i++) {
+ char *p = data_end - MIN(2048, cnts[i] * 32);
+ cfd->charcount = cnts[i];
+
+ cfd->chardata = p + 1;
+ sys_ioctl(-1, c, (uintptr_t) cfd);
+ printf("ioctl(-1, " XLAT_FMT
+ ", {charcount=%u, charheight=57005, chardata=",
+ XLAT_SEL(c, s), cnts[i]);
+ if (c == PIO_FONTX && cnts[i] * 32 > DEFAULT_STRLEN) {
+ print_quoted_hex(p + 1, DEFAULT_STRLEN);
+ printf("...}");
+ } else {
+ printf("%p}", p + 1);
+ }
+#if RETVAL_INJECTED
+ if (c == GIO_FONTX) {
+ printf(" => {charcount=%u, charheight=57005, chardata=",
+ cnts[i]);
+ if (cnts[i] * 32 > DEFAULT_STRLEN) {
+ print_quoted_hex(p + 1, DEFAULT_STRLEN);
+ printf("...}");
+ } else {
+ printf("%p}", p + 1);
+ }
+ }
+#endif
+ printf(") = " RETVAL);
+
+ cfd->chardata = p;
+ sys_ioctl(-1, c, (uintptr_t) cfd);
+ printf("ioctl(-1, " XLAT_FMT
+ ", {charcount=%u, charheight=57005, chardata=",
+ XLAT_SEL(c, s), cnts[i]);
+ if (c == PIO_FONTX) {
+ print_quoted_hex(p, MIN(DEFAULT_STRLEN, cnts[i] * 32));
+ if (cnts[i] * 32 > DEFAULT_STRLEN)
+ printf("...");
+ } else {
+ printf("%p", p);
+ }
+ printf("}");
+#if RETVAL_INJECTED
+ if (c == GIO_FONTX) {
+ printf(" => {charcount=%u, charheight=57005, chardata=",
+ cnts[i]);
+ print_quoted_hex(p, MIN(DEFAULT_STRLEN, cnts[i] * 32));
+ if (cnts[i] * 32 > DEFAULT_STRLEN)
+ printf("...");
+ printf("}");
+ }
+#endif
+ printf(") = " RETVAL);
+ }
+}
+
+/* GIO_CMAP, PIO_CMAP */
+static void
+check_cmap(unsigned int c, const char *s)
+{
+ char *cmap = tail_alloc(48);
+
+ fill_memory(cmap, 48);
+
+ check_null_invalid(c, s);
+
+ sys_ioctl(-1, c, (uintptr_t) (cmap + 1));
+ printf("ioctl(-1, " XLAT_FMT ", ", XLAT_SEL(c, s));
+ if ((c == PIO_CMAP || RETVAL_INJECTED) && (DEFAULT_STRLEN == 32)) {
+ printf("\"");
+ for (unsigned int i = 0; i < MIN(DEFAULT_STRLEN, 48); i++)
+ printf("\\x%x", 0x81 + i);
+ printf("\"...");
+ } else {
+ printf("%p", cmap + 1);
+ }
+ printf(") = " RETVAL);
+
+ sys_ioctl(-1, c, (uintptr_t) cmap);
+ printf("ioctl(-1, " XLAT_FMT ", ", XLAT_SEL(c, s));
+ if (c == PIO_CMAP || RETVAL_INJECTED) {
+ printf("\"");
+ for (unsigned int i = 0; i < MIN(DEFAULT_STRLEN, 48); i++)
+ printf("\\x%x", 0x80 + i);
+#if DEFAULT_STRLEN == 32
+ printf("\"...");
+#else
+ printf("\"");
+#endif
+ } else {
+ printf("%p", cmap);
+ }
+ printf(") = " RETVAL);
+}
+
+/* KDGKBDIACRUC, KDSKBDIACRUC */
+static void
+check_diacruc(unsigned int c, const char *s)
+{
+ struct kbdiacrsuc *diacrs0 = tail_alloc(sizeof(diacrs0->kb_cnt));
+ struct kbdiacrsuc *diacrs1 = tail_alloc(sizeof(diacrs1->kb_cnt) +
+ 4 * sizeof(struct kbdiacruc));
+ struct kbdiacrsuc *diacrs2 = tail_alloc(sizeof(*diacrs2));
+
+ int saved_errno;
+
+ check_null_invalid(c, s);
+
+ for (size_t i = 0; i < 2; i++) {
+ diacrs0->kb_cnt = i;
+ sys_ioctl(-1, c, (uintptr_t) diacrs0);
+ saved_errno = errno;
+ printf("ioctl(-1, " XLAT_FMT ", ", XLAT_SEL(c, s));
+ if (RETVAL_INJECTED || c == KDSKBDIACRUC) {
+ printf("{kb_cnt=%zu, kbdiacruc=", i);
+ if (i)
+ printf("%p}", diacrs0->kbdiacruc);
+ else
+ printf("[]}");
+ } else {
+ printf("%p", diacrs0);
+ }
+ errno = saved_errno;
+ printf(") = " RETVAL);
+ }
+
+ fill_memory32(diacrs1->kbdiacruc, 4 * sizeof(struct kbdiacruc));
+ for (size_t i = 0; i < 7; i++) {
+ diacrs1->kb_cnt = i;
+ sys_ioctl(-1, c, (uintptr_t) diacrs1);
+ saved_errno = errno;
+ printf("ioctl(-1, " XLAT_FMT ", ", XLAT_SEL(c, s));
+ if (RETVAL_INJECTED || c == KDSKBDIACRUC) {
+ printf("{kb_cnt=%zu, kbdiacruc=[", i);
+ for (size_t j = 0; j < MIN(i, 4); j++)
+ printf("%s{diacr=%#x, base=%#x, result=%#x}",
+ j ? ", " : "",
+ (unsigned int) (0x80a0c0e0 + j * 3),
+ (unsigned int) (0x80a0c0e1 + j * 3),
+ (unsigned int) (0x80a0c0e2 + j * 3));
+
+ if (i > 4) {
+ printf(", ... /* %p */",
+ diacrs1->kbdiacruc + 4);
+ }
+ printf("]}");
+ } else {
+ printf("%p", diacrs1);
+ }
+ errno = saved_errno;
+ printf(") = " RETVAL);
+ }
+
+ fill_memory32(diacrs2->kbdiacruc, sizeof(diacrs2->kbdiacruc));
+
+ for (size_t i = ARRAY_SIZE(diacrs2->kbdiacruc) - 1;
+ i < ARRAY_SIZE(diacrs2->kbdiacruc) + 3; i++) {
+ diacrs2->kb_cnt = i;
+ sys_ioctl(-1, c, (uintptr_t) diacrs2);
+ printf("ioctl(-1, " XLAT_FMT ", ", XLAT_SEL(c, s));
+ saved_errno = errno;
+ if (RETVAL_INJECTED || c == KDSKBDIACRUC) {
+ printf("{kb_cnt=%zu, kbdiacruc=[", i);
+ for (size_t j = 0;
+ j < MIN(i, MIN(ARRAY_SIZE(diacrs2->kbdiacruc),
+ DEFAULT_STRLEN)); j++)
+ printf("%s{diacr=%#x, base=%#x, result=%#x}",
+ j ? ", " : "",
+ (unsigned int) (0x80a0c0e0 + j * 3),
+ (unsigned int) (0x80a0c0e1 + j * 3),
+ (unsigned int) (0x80a0c0e2 + j * 3));
+
+ if (i > MIN(DEFAULT_STRLEN,
+ ARRAY_SIZE(diacrs2->kbdiacruc)))
+ printf(", ...");
+ printf("]}");
+ } else {
+ printf("%p", diacrs2);
+ }
+ errno = saved_errno;
+ printf(") = " RETVAL);
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ static const kernel_ulong_t magic =
+ (kernel_ulong_t) 0xdeadbeefbadc0dedULL;
+
+ static const uint32_t unknown_ioctls[] = {
+ 0xfffffff1, 0xc0007fff, 0xfffb800c, 0xfff8c000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xf3ffffff,
+ };
+
+ enum { MAP_ELEM_BIT = sizeof(unknown_ioctls[0]) * CHAR_BIT };
+
+ long rc;
+
+#if RETVAL_INJECTED
+ unsigned long num_skip;
+ bool locked = false;
+
+ if (argc < 2)
+ error_msg_and_fail("Usage: %s NUM_SKIP", argv[0]);
+
+ num_skip = strtoul(argv[1], NULL, 0);
+
+ for (unsigned int i = 0; i < num_skip; i++) {
+ long rc = sys_ioctl(-1, KDGETLED, 0);
+ printf("ioctl(-1, " XLAT_FMT ", NULL) = %s%s\n",
+ XLAT_ARGS(KDGETLED), sprintrc(rc),
+ rc == 42 ? " (INJECTED)" : "");
+
+ if (rc != 42)
+ continue;
+
+ locked = true;
+ break;
+ }
+
+ if (!locked)
+ error_msg_and_fail("Have not locked on ioctl(-1"
+ ", KDGETLED, NULL) returning 42");
+#endif
+
+ for (size_t i = 0; i < ARRAY_SIZE(unknown_ioctls); i++) {
+ for (size_t j = 0; j < MAP_ELEM_BIT; j++) {
+ if (!((unknown_ioctls[i] >> j) & 1))
+ continue;
+
+ const unsigned int id = i * MAP_ELEM_BIT + j;
+
+ sys_ioctl(-1, 'K' << 8 | id, magic);
+ printf("ioctl(-1, "
+ NABBR("%#x") VERB(" /* ")
+ NRAW("_IOC(%s, 0x4b, %#x, 0)") VERB(" */")
+ ", %#lx) = " RETVAL,
+#if XLAT_RAW || XLAT_VERBOSE
+ 'K' << 8 | id,
+#endif
+#if !XLAT_RAW
+ _IOC_NONE ? "0" : "_IOC_NONE", id,
+#endif
+ (unsigned long) magic);
+ }
+ }
+
+
+ /* KIOCSOUND */
+ sys_ioctl(-1, KIOCSOUND, 0);
+ printf("ioctl(-1, " XLAT_FMT ", 0" NRAW(" /* off */") ") = " RETVAL,
+ XLAT_ARGS(KIOCSOUND));
+
+ sys_ioctl(-1, KIOCSOUND, 1);
+ printf("ioctl(-1, " XLAT_FMT ", 1" NRAW(" /* 1193182 Hz */")
+ ") = " RETVAL, XLAT_ARGS(KIOCSOUND));
+
+ sys_ioctl(-1, KIOCSOUND, 440);
+ printf("ioctl(-1, " XLAT_FMT ", 440" NRAW(" /* 2711 Hz */")
+ ") = " RETVAL, XLAT_ARGS(KIOCSOUND));
+
+ sys_ioctl(-1, KIOCSOUND, 1193182);
+ printf("ioctl(-1, " XLAT_FMT ", 1193182" NRAW(" /* 1 Hz */")
+ ") = " RETVAL, XLAT_ARGS(KIOCSOUND));
+
+ sys_ioctl(-1, KIOCSOUND, 1193183);
+ printf("ioctl(-1, " XLAT_FMT ", 1193183" NRAW(" /* off */")
+ ") = " RETVAL, XLAT_ARGS(KIOCSOUND));
+
+ sys_ioctl(-1, KIOCSOUND,
+ (kernel_ulong_t) (0xbadc0ded00000000ULL | 2710));
+ printf("ioctl(-1, " XLAT_FMT
+#if SIZEOF_LONG == 4
+ ", 2710" NRAW(" /* 440 Hz */")
+#else
+ ", 13464652297489353366" NRAW(" /* off */")
+#endif
+ ") = " RETVAL, XLAT_ARGS(KIOCSOUND));
+
+ sys_ioctl(-1, KIOCSOUND, (kernel_ulong_t) 0xbadc0deddeadfaceULL);
+ printf("ioctl(-1, " XLAT_FMT
+#if SIZEOF_LONG == 8
+ ", 13464652301225294542"
+#else
+ ", 3735943886"
+#endif
+ NRAW(" /* off */") ") = " RETVAL, XLAT_ARGS(KIOCSOUND));
+
+ /* KDMKTONE */
+ sys_ioctl(-1, KDMKTONE, 0);
+ printf("ioctl(-1, " XLAT_FMT ", 0" NRAW(" /* off */") ") = " RETVAL,
+ XLAT_ARGS(KDMKTONE));
+
+ sys_ioctl(-1, KDMKTONE, 440);
+ printf("ioctl(-1, " XLAT_FMT ", 440" NRAW(" /* off */") ") = " RETVAL,
+ XLAT_ARGS(KDMKTONE));
+
+ sys_ioctl(-1, KDMKTONE, 0xffff);
+ printf("ioctl(-1, " XLAT_FMT ", 65535" NRAW(" /* off */") ") = " RETVAL,
+ XLAT_ARGS(KDMKTONE));
+
+ sys_ioctl(-1, KDMKTONE, 0x10000);
+ printf("ioctl(-1, " XLAT_FMT ", 1<<16|0" NRAW(" /* off */")
+ ") = " RETVAL, XLAT_ARGS(KDMKTONE));
+
+ sys_ioctl(-1, KDMKTONE,
+ (kernel_ulong_t) (0xbadc0ded00000000ULL | 0x10001));
+ printf("ioctl(-1, " XLAT_FMT ", 1<<16|1" NRAW(" /* 1193182 Hz, 1 ms */")
+ ") = " RETVAL, XLAT_ARGS(KDMKTONE));
+
+ sys_ioctl(-1, KDMKTONE, 0x1ffff);
+ printf("ioctl(-1, " XLAT_FMT ", 1<<16|65535" NRAW(" /* 18 Hz, 1 ms */")
+ ") = " RETVAL, XLAT_ARGS(KDMKTONE));
+
+ sys_ioctl(-1, KDMKTONE, (kernel_ulong_t) 0xbadc0deddeadfaceULL);
+ printf("ioctl(-1, " XLAT_FMT ", 57005<<16|64206"
+ NRAW(" /* 18 Hz, 57005 ms */") ") = " RETVAL,
+ XLAT_ARGS(KDMKTONE));
+
+
+ /* KDGETLED */
+ static const struct arg_val led_vecs[] = {
+ { ARG_STR(0) },
+ { ARG_XLAT_KNOWN(0x1, "LED_SCR") },
+ { ARG_XLAT_KNOWN(0x7, "LED_SCR|LED_NUM|LED_CAP") },
+ { ARG_XLAT_KNOWN(0xfe, "LED_NUM|LED_CAP|0xf8") },
+ { (kernel_ulong_t) 0xbadc0dedfeedfaf0ULL,
+ XLAT_UNKNOWN(0xf0, "LED_???") },
+ };
+
+ unsigned char *leds = tail_alloc(sizeof(*leds));
+
+ check_null_invalid(ARG_STR(KDGETLED));
+
+ for (size_t i = 0; i < ARRAY_SIZE(led_vecs); i++) {
+ *leds = led_vecs[i].val;
+ rc = sys_ioctl(-1, KDGETLED, (uintptr_t) leds);
+ if (rc >= 0) {
+ printf("ioctl(-1, " XLAT_FMT ", [%s]) = " RETVAL,
+ XLAT_ARGS(KDGETLED), led_vecs[i].str);
+ } else {
+ printf("ioctl(-1, " XLAT_FMT ", %p) = " RETVAL,
+ XLAT_ARGS(KDGETLED), leds);
+ }
+ }
+
+
+ /* KDSETLED */
+ for (size_t i = 0; i < ARRAY_SIZE(led_vecs); i++) {
+ sys_ioctl(-1, KDSETLED, led_vecs[i].val);
+ printf("ioctl(-1, " XLAT_FMT ", %s) = " RETVAL,
+ XLAT_ARGS(KDSETLED), led_vecs[i].str);
+ }
+
+ sys_ioctl(-1, KDSETLED, (kernel_ulong_t) 0xdeadc0defeedfaceULL);
+ printf("ioctl(-1, " XLAT_FMT ", %s) = " RETVAL,
+ XLAT_ARGS(KDSETLED), XLAT_STR(LED_NUM|LED_CAP|0xc8));
+
+
+ /* KDGKBTYPE */
+ static const struct arg_val kbt_vecs[] = {
+ { ARG_XLAT_UNKNOWN(0, "KB_???") },
+ { ARG_XLAT_KNOWN(0x1, "KB_84") },
+ { ARG_XLAT_KNOWN(0x2, "KB_101") },
+ { ARG_XLAT_KNOWN(0x3, "KB_OTHER") },
+ { ARG_XLAT_UNKNOWN(0x4, "KB_???") },
+ { (kernel_ulong_t) 0xbadc0dedcacafefeULL,
+ XLAT_UNKNOWN(0xfe, "KB_???") },
+ };
+
+ unsigned char *kbt = tail_alloc(sizeof(*kbt));
+
+ check_null_invalid(ARG_STR(KDGKBTYPE));
+
+ for (size_t i = 0; i < ARRAY_SIZE(kbt_vecs); i++) {
+ *kbt = kbt_vecs[i].val;
+ rc = sys_ioctl(-1, KDGKBTYPE, (uintptr_t) kbt);
+ if (rc >= 0) {
+ printf("ioctl(-1, " XLAT_FMT ", [%s]) = " RETVAL,
+ XLAT_ARGS(KDGKBTYPE), kbt_vecs[i].str);
+ } else {
+ printf("ioctl(-1, " XLAT_FMT ", %p) = " RETVAL,
+ XLAT_ARGS(KDGKBTYPE), kbt);
+ }
+ }
+
+
+ /* KDADDIO */
+ static const struct arg_val iop_vecs[] = {
+ { ARG_STR(0) },
+ { ARG_STR(0x3b3) },
+ { ARG_STR(0x3b4) NRAW(" /* GPFIRST + 0 */") },
+ { ARG_STR(0x3c0) NRAW(" /* GPFIRST + 12 */") },
+ { ARG_STR(0x3df) NRAW(" /* GPFIRST + 43 */") },
+ { ARG_STR(0x3e0) },
+ { ARG_STR(0xdeadc0de) },
+ { (kernel_ulong_t) 0xbadc0dedfacefeedULL,
+#if SIZEOF_LONG > 4
+ "0xbadc0dedfacefeed"
+#else
+ "0xfacefeed"
+#endif
+ },
+ };
+
+ for (size_t i = 0; i < ARRAY_SIZE(iop_vecs); i++) {
+ sys_ioctl(-1, KDADDIO, iop_vecs[i].val);
+ printf("ioctl(-1, " XLAT_FMT ", %s) = " RETVAL,
+ XLAT_ARGS(KDADDIO), iop_vecs[i].str);
+ }
+
+
+ /* KDDELIO */
+ for (size_t i = 0; i < ARRAY_SIZE(iop_vecs); i++) {
+ sys_ioctl(-1, KDDELIO, iop_vecs[i].val);
+ printf("ioctl(-1, " XLAT_FMT ", %s) = " RETVAL,
+ XLAT_ARGS(KDDELIO), iop_vecs[i].str);
+ }
+
+
+ /* KDENABIO */
+ sys_ioctl(-1, KDENABIO, (kernel_ulong_t) 0xbadc0deddeadface);
+ printf("ioctl(-1, " XLAT_FMT ") = " RETVAL, XLAT_ARGS(KDENABIO));
+
+
+ /* KDDISABIO */
+ sys_ioctl(-1, KDDISABIO, (kernel_ulong_t) 0xbadc0deddeadface);
+ printf("ioctl(-1, " XLAT_FMT ") = " RETVAL, XLAT_ARGS(KDDISABIO));
+
+
+ /* KDSETMODE */
+ static const struct arg_val mode_vecs[] = {
+ { ARG_XLAT_KNOWN(0, "KD_TEXT") },
+ { ARG_XLAT_KNOWN(0x1, "KD_GRAPHICS") },
+ { ARG_XLAT_KNOWN(0x3, "KD_TEXT1") },
+ { ARG_XLAT_UNKNOWN(0x4, "KD_???") },
+ { (kernel_ulong_t) 0xbadc0dedcacafefeULL,
+ "0xcacafefe" NRAW(" /* KD_??? */") },
+ };
+
+ for (size_t i = 0; i < ARRAY_SIZE(mode_vecs); i++) {
+ sys_ioctl(-1, KDSETMODE, mode_vecs[i].val);
+ printf("ioctl(-1, " XLAT_FMT ", %s) = " RETVAL,
+ XLAT_ARGS(KDSETMODE), mode_vecs[i].str);
+ }
+
+
+ /* KDGETMODE */
+ unsigned int *mode = tail_alloc(sizeof(*mode));
+
+ check_null_invalid(ARG_STR(KDGETMODE));
+
+ for (size_t i = 0; i < ARRAY_SIZE(mode_vecs); i++) {
+ *mode = mode_vecs[i].val;
+ rc = sys_ioctl(-1, KDGETMODE, (uintptr_t) mode);
+ if (rc >= 0) {
+ printf("ioctl(-1, " XLAT_FMT ", [%s]) = " RETVAL,
+ XLAT_ARGS(KDGETMODE), mode_vecs[i].str);
+ } else {
+ printf("ioctl(-1, " XLAT_FMT ", %p) = " RETVAL,
+ XLAT_ARGS(KDGETMODE), mode);
+ }
+ }
+
+
+ /* KDMAPDISP */
+ sys_ioctl(-1, KDMAPDISP, (kernel_ulong_t) 0xbadc0deddeadface);
+ printf("ioctl(-1, " XLAT_FMT ") = " RETVAL, XLAT_ARGS(KDMAPDISP));
+
+
+ /* KDUNMAPDISP */
+ sys_ioctl(-1, KDUNMAPDISP, (kernel_ulong_t) 0xbadc0deddeadface);
+ printf("ioctl(-1, " XLAT_FMT ") = " RETVAL, XLAT_ARGS(KDUNMAPDISP));
+
+
+ /* GIO_SCRNMAP */
+ check_scrnmap(ARG_STR(GIO_SCRNMAP));
+
+
+ /* PIO_SCRNMAP */
+ check_scrnmap(ARG_STR(PIO_SCRNMAP));
+
+
+ /* KDGKBMODE */
+ static const struct arg_val kbmode_vecs[] = {
+ { ARG_XLAT_UNKNOWN(-1, "K_???") },
+ { ARG_XLAT_KNOWN(0, "K_RAW") },
+ { ARG_XLAT_KNOWN(1, "K_XLATE") },
+ { ARG_XLAT_KNOWN(4, "K_OFF") },
+ { ARG_XLAT_UNKNOWN(5, "K_???") },
+ { (kernel_ulong_t) 0xbadc0dedfeeddeadULL,
+ XLAT_UNKNOWN(-17965395, "K_???") },
+ };
+
+ check_null_invalid(ARG_STR(KDGKBMODE));
+
+ for (size_t i = 0; i < ARRAY_SIZE(kbmode_vecs); i++) {
+ *mode = kbmode_vecs[i].val;
+ rc = sys_ioctl(-1, KDGKBMODE, (uintptr_t) mode);
+ if (rc >= 0) {
+ printf("ioctl(-1, " XLAT_FMT ", [%s]) = " RETVAL,
+ XLAT_ARGS(KDGKBMODE), kbmode_vecs[i].str);
+ } else {
+ printf("ioctl(-1, " XLAT_FMT ", %p) = " RETVAL,
+ XLAT_ARGS(KDGKBMODE), mode);
+ }
+ }
+
+
+ /* KDSKBMODE */
+ for (size_t i = 0; i < ARRAY_SIZE(kbmode_vecs); i++) {
+ sys_ioctl(-1, KDSKBMODE, kbmode_vecs[i].val);
+ printf("ioctl(-1, " XLAT_FMT ", %s) = " RETVAL,
+ XLAT_ARGS(KDSKBMODE), kbmode_vecs[i].str);
+ }
+
+
+ /* KDGKBENT */
+ check_kbdent(ARG_STR(KDGKBENT));
+
+
+ /* KDSKBENT */
+ check_kbdent(ARG_STR(KDSKBENT));
+
+
+ /* KDGKBSENT */
+ check_kbdsent(ARG_STR(KDGKBSENT));
+
+
+ /* KDSKBSENT */
+ check_kbdsent(ARG_STR(KDSKBSENT));
+
+
+ /* KDGKBDIACR */
+ check_diacr(ARG_STR(KDGKBDIACR));
+
+
+ /* KDSKBDIACR */
+ check_diacr(ARG_STR(KDSKBDIACR));
+
+
+ /* KDGETKEYCODE */
+ check_xetkeycode(ARG_STR(KDGETKEYCODE));
+
+
+ /* KDSETKEYCODE */
+ check_xetkeycode(ARG_STR(KDSETKEYCODE));
+
+
+ /* KDSIGACCEPT */
+ static const struct {
+ kernel_ulong_t val;
+ const char *str;
+ } sigaccept_vecs[] = {
+ { (kernel_ulong_t) -1ULL,
+ SIZEOF_LONG == 8 ? "18446744073709551615" : "4294967295" },
+ { 0, "0" },
+ { ARG_XLAT_KNOWN(SIGHUP, "SIGHUP") },
+ { ARG_XLAT_KNOWN(SIGUSR1, "SIGUSR1") },
+ { ARG_XLAT_KNOWN(32, "SIGRTMIN") },
+ { ARG_XLAT_KNOWN(33, "SIGRT_1") },
+ { ARG_STR(128) },
+ };
+
+ for (size_t i = 0; i < ARRAY_SIZE(sigaccept_vecs); i++) {
+ sys_ioctl(-1, KDSIGACCEPT, sigaccept_vecs[i].val);
+ printf("ioctl(-1, " XLAT_FMT ", %s) = " RETVAL,
+ XLAT_ARGS(KDSIGACCEPT), sigaccept_vecs[i].str);
+ }
+
+
+ /* KDKBDREP */
+ check_kbdrep(ARG_STR(KDKBDREP));
+
+
+ /* GIO_FONT */
+ check_font(ARG_STR(GIO_FONT));
+
+
+ /* PIO_FONT */
+ check_font(ARG_STR(PIO_FONT));
+
+
+ /* KDGKBMETA */
+ static const struct {
+ kernel_ulong_t arg;
+ const char *str;
+ } meta_vecs[] = {
+ { ARG_XLAT_UNKNOWN(0, "K_???") },
+ { ARG_XLAT_UNKNOWN(0x1, "K_???") },
+ { ARG_XLAT_UNKNOWN(0x2, "K_???") },
+ { ARG_XLAT_KNOWN(0x3, "K_METABIT") },
+ { ARG_XLAT_KNOWN(0x4, "K_ESCPREFIX") },
+ { ARG_XLAT_UNKNOWN(0x5, "K_???") },
+ { (kernel_ulong_t) 0xdeadfacebeeffeedULL,
+ "0xbeeffeed" NRAW(" /* K_??? */") },
+ };
+ int *meta = tail_alloc(sizeof(*meta));
+
+ check_null_invalid(ARG_STR(KDGKBMETA));
+
+ for (size_t i = 0; i < ARRAY_SIZE(meta_vecs); i++) {
+ *meta = meta_vecs[i].arg;
+ sys_ioctl(-1, KDGKBMETA, (uintptr_t) meta);
+ printf("ioctl(-1, " XLAT_FMT ", ", XLAT_ARGS(KDGKBMETA));
+#if RETVAL_INJECTED
+ printf("[%s]", meta_vecs[i].str);
+#else
+ printf("%p", meta);
+#endif
+ printf(") = " RETVAL);
+ }
+
+
+ /* KDSKBMETA */
+ for (size_t i = 0; i < ARRAY_SIZE(meta_vecs); i++) {
+ sys_ioctl(-1, KDSKBMETA, meta_vecs[i].arg);
+ printf("ioctl(-1, " XLAT_FMT ", %s) = " RETVAL,
+ XLAT_ARGS(KDSKBMETA), meta_vecs[i].str);
+ }
+
+
+ /* KDGKBLED */
+ static const struct arg_val kbled_vecs[] = {
+ { ARG_STR(0) },
+ { ARG_XLAT_KNOWN(0x1, "LED_SCR") },
+ { ARG_XLAT_KNOWN(0x7, "LED_SCR|LED_NUM|LED_CAP") },
+ { ARG_XLAT_KNOWN(0x10, "LED_SCR<<4") },
+ { ARG_XLAT_KNOWN(0x70, "LED_SCR<<4|LED_NUM<<4|LED_CAP<<4") },
+ { ARG_XLAT_KNOWN(0xfe, "LED_NUM|LED_CAP|LED_SCR<<4|LED_NUM<<4"
+ "|LED_CAP<<4|0x88") },
+ { (kernel_ulong_t) 0xbadc0dedfeedfa88ULL,
+ XLAT_UNKNOWN(0x88, "LED_???") },
+ };
+
+ unsigned char *kbleds = tail_alloc(sizeof(*kbleds));
+
+ check_null_invalid(ARG_STR(KDGKBLED));
+
+ for (size_t i = 0; i < ARRAY_SIZE(kbled_vecs); i++) {
+ *kbleds = kbled_vecs[i].val;
+ rc = sys_ioctl(-1, KDGKBLED, (uintptr_t) kbleds);
+ if (rc >= 0) {
+ printf("ioctl(-1, " XLAT_FMT ", [%s]) = " RETVAL,
+ XLAT_ARGS(KDGKBLED), kbled_vecs[i].str);
+ } else {
+ printf("ioctl(-1, " XLAT_FMT ", %p) = " RETVAL,
+ XLAT_ARGS(KDGKBLED), kbleds);
+ }
+ }
+
+
+ /* KDSKBLED */
+ for (size_t i = 0; i < ARRAY_SIZE(kbled_vecs); i++) {
+ sys_ioctl(-1, KDSKBLED, kbled_vecs[i].val);
+ printf("ioctl(-1, " XLAT_FMT ", %s) = " RETVAL,
+ XLAT_ARGS(KDSKBLED), kbled_vecs[i].str);
+ }
+
+
+ /* GIO_UNIMAP */
+ check_unimap(ARG_STR(GIO_UNIMAP));
+
+
+ /* PIO_UNIMAP */
+ check_unimap(ARG_STR(PIO_UNIMAP));
+
+
+ /* PIO_UNIMAPCLR */
+ struct unimapinit *umi = tail_alloc(sizeof(*umi));
+
+ check_null_invalid(ARG_STR(PIO_UNIMAPCLR));
+
+ sys_ioctl(-1, PIO_UNIMAPCLR, (uintptr_t) umi + 2);
+ printf("ioctl(-1, " XLAT_FMT ", %p) = " RETVAL,
+ XLAT_ARGS(PIO_UNIMAPCLR), (char *) umi + 2);
+
+ memset(umi, 0, sizeof(*umi));
+ sys_ioctl(-1, PIO_UNIMAPCLR, (uintptr_t) umi);
+ printf("ioctl(-1, " XLAT_FMT ", {advised_hashsize=0"
+ ", advised_hashstep=0, advised_hashlevel=0}) = " RETVAL,
+ XLAT_ARGS(PIO_UNIMAPCLR));
+
+ fill_memory16(umi, sizeof(*umi));
+ sys_ioctl(-1, PIO_UNIMAPCLR, (uintptr_t) umi);
+ printf("ioctl(-1, " XLAT_FMT ", {advised_hashsize=32960"
+ ", advised_hashstep=32961, advised_hashlevel=32962}) = " RETVAL,
+ XLAT_ARGS(PIO_UNIMAPCLR));
+
+
+ /* GIO_UNISCRNMAP */
+ check_uniscrnmap(ARG_STR(GIO_UNISCRNMAP));
+
+
+ /* PIO_UNISCRNMAP */
+ check_uniscrnmap(ARG_STR(PIO_UNISCRNMAP));
+
+
+ /* GIO_FONTX */
+ check_fontx(ARG_STR(GIO_FONTX));
+
+
+ /* PIO_FONTX */
+ check_fontx(ARG_STR(GIO_FONTX));
+
+
+ /* PIO_FONTRESET */
+ sys_ioctl(-1, PIO_FONTRESET, (kernel_ulong_t) 0xbadc0deddeadface);
+ printf("ioctl(-1, " XLAT_FMT ") = " RETVAL, XLAT_ARGS(PIO_FONTRESET));
+
+
+ /* GIO_CMAP */
+ check_cmap(ARG_STR(GIO_CMAP));
+
+
+ /* PIO_CMAP */
+ check_cmap(ARG_STR(PIO_CMAP));
+
+
+ /* KDFONTOP */
+ struct console_font_op *cfo = tail_alloc(sizeof(*cfo));
+ unsigned char *cfo_data = tail_alloc(2048);
+ unsigned char *cfo_data_end = cfo_data + 2048;
+
+ fill_memory(cfo_data, 2048);
+
+ check_null_invalid(ARG_STR(KDFONTOP));
+
+ cfo->op = 4;
+ cfo->flags = 0xdeadbeef;
+ cfo->width = 0xbadc0ded;
+ cfo->height = 0xfacecafe;
+ cfo->charcount = 0xdadfaded;
+ cfo->data = NULL;
+ sys_ioctl(-1, KDFONTOP, (uintptr_t) cfo);
+ printf("ioctl(-1, " XLAT_FMT ", {op=0x4" NRAW(" /* KD_FONT_OP_??? */")
+ ", flags=" XLAT_KNOWN(0xdeadbeef, "KD_FONT_FLAG_DONT_RECALC"
+ "|KD_FONT_FLAG_OLD|0x5eadbeee")
+ ", width=3134983661, height=4207856382, charcount=3672092141"
+ ", data=NULL}"
+#if RETVAL_INJECTED
+ " => {width=3134983661, height=4207856382, charcount=3672092141"
+ ", data=NULL}"
+#endif
+ ") = " RETVAL, XLAT_ARGS(KDFONTOP));
+
+ cfo->op = 0xbeefface;
+ cfo->flags = 0x5a1ecafe;;
+ cfo->data = (unsigned char *) cfo;
+ sys_ioctl(-1, KDFONTOP, (uintptr_t) cfo);
+ printf("ioctl(-1, " XLAT_FMT ", {op=0xbeefface"
+ NRAW(" /* KD_FONT_OP_??? */")
+ ", flags=0x5a1ecafe" NRAW(" /* KD_FONT_FLAG_??? */")
+ ", width=3134983661, height=4207856382, charcount=3672092141"
+ ", data=%p}"
+#if RETVAL_INJECTED
+ " => {width=3134983661, height=4207856382, charcount=3672092141"
+ ", data=%p}"
+#endif
+ ") = " RETVAL, XLAT_ARGS(KDFONTOP), cfo
+#if RETVAL_INJECTED
+ , cfo
+#endif
+ );
+
+ static const struct strval32 kdfont_ops[] = {
+ { ARG_XLAT_KNOWN(0, "KD_FONT_OP_SET") },
+ { ARG_XLAT_KNOWN(0x1, "KD_FONT_OP_GET") },
+ };
+
+ for (size_t i = 0; i < ARRAY_SIZE(kdfont_ops); i++) {
+ cfo->op = kdfont_ops[i].val;
+ cfo->flags = 1;
+ cfo->width = 0;
+ cfo->height = 0;
+ cfo->charcount = 0;
+ cfo->data = NULL;
+ sys_ioctl(-1, KDFONTOP, (uintptr_t) cfo);
+ printf("ioctl(-1, " XLAT_FMT ", {op=%s, flags="
+ XLAT_FMT ", width=0, height=0, charcount=0, data=NULL}",
+ XLAT_ARGS(KDFONTOP), kdfont_ops[i].str,
+ XLAT_ARGS(KD_FONT_FLAG_DONT_RECALC));
+ if (kdfont_ops[i].val == KD_FONT_OP_GET && RETVAL_INJECTED) {
+ printf(" => {width=0, height=0, charcount=0"
+ ", data=NULL}");
+ }
+ printf(") = " RETVAL);
+
+ cfo->data = cfo_data_end;
+ for (size_t j = 0; j < 2; j++) {
+ cfo->charcount = j;
+ sys_ioctl(-1, KDFONTOP, (uintptr_t) cfo);
+ printf("ioctl(-1, " XLAT_FMT ", {op=%s, flags="
+ XLAT_FMT ", width=0, height=0, charcount=%zu"
+ ", data=",
+ XLAT_ARGS(KDFONTOP), kdfont_ops[i].str,
+ XLAT_ARGS(KD_FONT_FLAG_DONT_RECALC), j);
+ if (kdfont_ops[i].val == KD_FONT_OP_SET)
+ printf("\"\"");
+ else
+ printf("%p", cfo_data_end);
+#if RETVAL_INJECTED
+ if (kdfont_ops[i].val == KD_FONT_OP_GET) {
+ printf("} => {width=0, height=0, charcount=%zu"
+ ", data=\"\"", j);
+ }
+#endif
+ printf("}) = " RETVAL);
+
+ }
+
+ cfo->flags = 0;
+ cfo->width = 1;
+ cfo->data = cfo_data_end - 31;
+ sys_ioctl(-1, KDFONTOP, (uintptr_t) cfo);
+ printf("ioctl(-1, " XLAT_FMT ", {op=%s, flags=0, width=1"
+ ", height=0, charcount=1, data=%p}",
+ XLAT_ARGS(KDFONTOP), kdfont_ops[i].str,
+ cfo_data_end - 31);
+ if (kdfont_ops[i].val == KD_FONT_OP_GET && RETVAL_INJECTED) {
+ printf(" => {width=1, height=0, charcount=1, data=%p}",
+ cfo_data_end - 31);
+ }
+ printf(") = " RETVAL);
+
+ cfo->data = cfo_data_end - 32;
+ sys_ioctl(-1, KDFONTOP, (uintptr_t) cfo);
+ printf("ioctl(-1, " XLAT_FMT ", {op=%s, flags=0, width=1"
+ ", height=0, charcount=1, data=",
+ XLAT_ARGS(KDFONTOP), kdfont_ops[i].str);
+ if (kdfont_ops[i].val == KD_FONT_OP_SET)
+ print_quoted_hex(cfo_data_end - 32, 32);
+ else
+ printf("%p", cfo_data_end - 32);
+ if (kdfont_ops[i].val == KD_FONT_OP_GET && RETVAL_INJECTED) {
+ printf("} => {width=1, height=0, charcount=1, data=");
+ print_quoted_hex(cfo_data_end - 32, 32);
+
+ }
+ printf("}) = " RETVAL);
+
+ cfo->charcount = 32;
+ cfo->data = cfo_data_end - 1023;
+ sys_ioctl(-1, KDFONTOP, (uintptr_t) cfo);
+ printf("ioctl(-1, " XLAT_FMT ", {op=%s, flags=0, width=1"
+ ", height=0, charcount=32, data=",
+ XLAT_ARGS(KDFONTOP), kdfont_ops[i].str);
+ if (kdfont_ops[i].val == KD_FONT_OP_SET && DEFAULT_STRLEN == 32)
+ {
+ print_quoted_hex(cfo_data_end - 1023, 32);
+ printf("...");
+ } else {
+ printf("%p", cfo_data_end - 1023);
+ }
+ if (kdfont_ops[i].val == KD_FONT_OP_GET && RETVAL_INJECTED) {
+ printf("} => {width=1, height=0, charcount=32, data=");
+#if DEFAULT_STRLEN == 32
+ print_quoted_hex(cfo_data_end - 1023, 32);
+ printf("...");
+#else
+ printf("%p", cfo_data_end - 1023);
+#endif
+
+ }
+ printf("}) = " RETVAL);
+
+ cfo->data = cfo_data_end - 1024;
+ sys_ioctl(-1, KDFONTOP, (uintptr_t) cfo);
+ printf("ioctl(-1, " XLAT_FMT ", {op=%s, flags=0, width=1"
+ ", height=0, charcount=32, data=",
+ XLAT_ARGS(KDFONTOP), kdfont_ops[i].str);
+ if (kdfont_ops[i].val == KD_FONT_OP_SET) {
+ print_quoted_hex(cfo_data_end - 1024, DEFAULT_STRLEN);
+#if DEFAULT_STRLEN == 32
+ printf("...");
+#endif
+ } else {
+ printf("%p", cfo_data_end - 1024);
+ }
+ if (kdfont_ops[i].val == KD_FONT_OP_GET && RETVAL_INJECTED) {
+ printf("} => {width=1, height=0, charcount=32, data=");
+ print_quoted_hex(cfo_data_end - 1024, DEFAULT_STRLEN);
+#if DEFAULT_STRLEN == 32
+ printf("...");
+#endif
+ }
+ printf("}) = " RETVAL);
+
+ cfo->charcount = 256;
+ cfo->data = cfo_data_end - 1025;
+ sys_ioctl(-1, KDFONTOP, (uintptr_t) cfo);
+ printf("ioctl(-1, " XLAT_FMT ", {op=%s, flags=0, width=1"
+ ", height=0, charcount=256, data=",
+ XLAT_ARGS(KDFONTOP), kdfont_ops[i].str);
+ if (kdfont_ops[i].val == KD_FONT_OP_SET) {
+ print_quoted_hex(cfo_data_end - 1025, DEFAULT_STRLEN);
+ printf("...");
+ } else {
+ printf("%p", cfo_data_end - 1025);
+ }
+ if (kdfont_ops[i].val == KD_FONT_OP_GET && RETVAL_INJECTED) {
+ printf("} => {width=1, height=0, charcount=256, data=");
+ print_quoted_hex(cfo_data_end - 1025, DEFAULT_STRLEN);
+ printf("...");
+
+ }
+ printf("}) = " RETVAL);
+ }
+
+ cfo->op = 2;
+ cfo->data = NULL;
+ sys_ioctl(-1, KDFONTOP, (uintptr_t) cfo);
+ printf("ioctl(-1, " XLAT_FMT ", {op=" XLAT_FMT ", width=1, height=0"
+ ", data=NULL}"
+#if RETVAL_INJECTED
+ " => {width=1, height=0}"
+#endif
+ ") = " RETVAL,
+ XLAT_ARGS(KDFONTOP), XLAT_ARGS(KD_FONT_OP_SET_DEFAULT));
+
+ cfo->data = cfo_data_end - 1;
+ cfo->data[0] = '\0';
+ sys_ioctl(-1, KDFONTOP, (uintptr_t) cfo);
+ printf("ioctl(-1, " XLAT_FMT ", {op=" XLAT_FMT ", width=1, height=0"
+ ", data=\"\"}"
+#if RETVAL_INJECTED
+ " => {width=1, height=0}"
+#endif
+ ") = " RETVAL,
+ XLAT_ARGS(KDFONTOP), XLAT_ARGS(KD_FONT_OP_SET_DEFAULT));
+
+ cfo->data[0] = 'x';
+ sys_ioctl(-1, KDFONTOP, (uintptr_t) cfo);
+ printf("ioctl(-1, " XLAT_FMT ", {op=" XLAT_FMT ", width=1, height=0"
+ ", data=%p}"
+#if RETVAL_INJECTED
+ " => {width=1, height=0}"
+#endif
+ ") = " RETVAL,
+ XLAT_ARGS(KDFONTOP), XLAT_ARGS(KD_FONT_OP_SET_DEFAULT),
+ cfo_data_end - 1);
+
+ cfo->width = 0xcafebeef;
+ cfo->height = 0xbea7bee5;
+ cfo->data = cfo_data_end - 32;
+ strcpy((char *) cfo->data,
+ "\1\2\3\r\n\t\v\f\\\"OH\377HAI\7\10\02101234567890x");
+ for (size_t j = 0; j < 2; j++) {
+ sys_ioctl(-1, KDFONTOP, (uintptr_t) cfo);
+ printf("ioctl(-1, " XLAT_FMT ", {op=" XLAT_FMT
+ ", width=3405692655, height=3198664421, data=\"\\1\\2\\3"
+ "\\r\\n\\t\\v\\f\\\\\\\"OH\\377HAI\\7\\10\\0210123456789"
+ "0x\"%s}"
+#if RETVAL_INJECTED
+ " => {width=3405692655, height=3198664421}"
+#endif
+ ") = " RETVAL,
+ XLAT_ARGS(KDFONTOP), XLAT_ARGS(KD_FONT_OP_SET_DEFAULT),
+ j ? "..." : "");
+
+ cfo->data[31] = 'y';
+ }
+
+ cfo->op = 3;
+ cfo->height = 0;
+ sys_ioctl(-1, KDFONTOP, (uintptr_t) cfo);
+ printf("ioctl(-1, " XLAT_FMT ", {op=" XLAT_FMT ", height=0}) = " RETVAL,
+ XLAT_ARGS(KDFONTOP), XLAT_ARGS(KD_FONT_OP_COPY));
+
+
+ /* KDGKBDIACRUC */
+ check_diacruc(ARG_STR(KDGKBDIACRUC));
+
+
+ /* KDSKBDIACRUC */
+ check_diacruc(ARG_STR(KDSKBDIACRUC));
+
+
+ puts("+++ exited with 0 +++");
+ return 0;
+}
diff --git a/tests/pure_executables.list b/tests/pure_executables.list
index 6f47fd26b..2223337d4 100755
--- a/tests/pure_executables.list
+++ b/tests/pure_executables.list
@@ -205,6 +205,10 @@ ioctl_hdio-v-Xabbrev
ioctl_hdio-v-Xraw
ioctl_hdio-v-Xverbose
ioctl_inotify
+ioctl_kd
+ioctl_kd-Xabbrev
+ioctl_kd-Xraw
+ioctl_kd-Xverbose
ioctl_kvm_run
ioctl_kvm_run-v
ioctl_kvm_run_auxstr_vcpu