>From 6ddab7d3ba1035b5e2a6016bde4776436267c18b Mon Sep 17 00:00:00 2001 From: Luca Bonissi <[email protected]> Date: Fri, 31 Oct 2025 13:29:19 +0100 Subject: [PATCH 1/7] Add termios2 support to linux-user
Signed-off-by: Luca Bonissi <[email protected]> --- linux-user/ioctls.h | 6 +++ linux-user/strace.c | 69 ++++++++++++++++++++++++++++++ linux-user/syscall.c | 84 +++++++++++++++++++++++++++++++++++++ linux-user/syscall_types.h | 3 ++ linux-user/user-internals.h | 3 ++ 5 files changed, 165 insertions(+) diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index 2f62fd2cb9..6ecfe6306e 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -1,5 +1,11 @@ /* emulated ioctl list */ +#ifdef TARGET_TCGETS2 + IOCTL(TCGETS2, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios2))) + IOCTL(TCSETS2, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios2))) + IOCTL(TCSETSW2, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios2))) + IOCTL(TCSETSF2, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios2))) +#endif IOCTL(TCGETS, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios))) IOCTL(TCSETS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios))) IOCTL(TCSETSF, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios))) diff --git a/linux-user/strace.c b/linux-user/strace.c index 758c5d32b6..7afb94544f 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -1935,6 +1935,75 @@ print_termios(void *arg) qemu_log("}"); } +#ifdef TARGET_TCGETS2 +void +print_termios2(void *arg) +{ + const struct target_termios2 *target = arg; + + target_tcflag_t iflags = tswap32(target->c_iflag); + target_tcflag_t oflags = tswap32(target->c_oflag); + target_tcflag_t cflags = tswap32(target->c_cflag); + target_tcflag_t lflags = tswap32(target->c_lflag); + + qemu_log("{"); + + qemu_log("c_iflag = "); + print_flags(termios_iflags, iflags, 0); + + qemu_log("c_oflag = "); + target_tcflag_t oflags_clean = oflags & ~(TARGET_NLDLY | TARGET_CRDLY | + TARGET_TABDLY | TARGET_BSDLY | + TARGET_VTDLY | TARGET_FFDLY); + print_flags(termios_oflags, oflags_clean, 0); + if (oflags & TARGET_NLDLY) { + print_enums(termios_oflags_NLDLY, oflags & TARGET_NLDLY, 0); + } + if (oflags & TARGET_CRDLY) { + print_enums(termios_oflags_CRDLY, oflags & TARGET_CRDLY, 0); + } + if (oflags & TARGET_TABDLY) { + print_enums(termios_oflags_TABDLY, oflags & TARGET_TABDLY, 0); + } + if (oflags & TARGET_BSDLY) { + print_enums(termios_oflags_BSDLY, oflags & TARGET_BSDLY, 0); + } + if (oflags & TARGET_VTDLY) { + print_enums(termios_oflags_VTDLY, oflags & TARGET_VTDLY, 0); + } + if (oflags & TARGET_FFDLY) { + print_enums(termios_oflags_FFDLY, oflags & TARGET_FFDLY, 0); + } + + qemu_log("c_cflag = "); + if (cflags & TARGET_CBAUD) { + print_enums(termios_cflags_CBAUD, cflags & TARGET_CBAUD, 0); + } + if (cflags & TARGET_CSIZE) { + print_enums(termios_cflags_CSIZE, cflags & TARGET_CSIZE, 0); + } + target_tcflag_t cflags_clean = cflags & ~(TARGET_CBAUD | TARGET_CSIZE); + print_flags(termios_cflags, cflags_clean, 0); + + qemu_log("c_lflag = "); + print_flags(termios_lflags, lflags, 0); + + qemu_log("c_ispeed = "); + print_raw_param("%u", tswap32(target->c_ispeed), 0); + + qemu_log("c_ospeed = "); + print_raw_param("%u", tswap32(target->c_ospeed), 0); + + qemu_log("c_cc = "); + qemu_log("\"%s\",", target->c_cc); + + qemu_log("c_line = "); + print_raw_param("\'%c\'", target->c_line, 1); + + qemu_log("}"); +} +#endif + #undef UNUSED #ifdef TARGET_NR_accept diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 8546f48a05..920bf23406 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -86,6 +86,7 @@ #endif #define termios host_termios +#define termios2 host_termios2 #define winsize host_winsize #define termio host_termio #define sgttyb host_sgttyb /* same as target */ @@ -5885,6 +5886,89 @@ static const StructEntry struct_termios_def = { .print = print_termios, }; +#ifdef TARGET_TCGETS2 +static void target_to_host_termios2 (void *dst, const void *src) +{ + struct host_termios2 *host = dst; + const struct target_termios2 *target = src; + + host->c_iflag = + target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl); + host->c_oflag = + target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl); + host->c_cflag = + target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl); + host->c_lflag = + target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl); + host->c_line = target->c_line; + host->c_ispeed = tswap32(target->c_ispeed); + host->c_ospeed = tswap32(target->c_ospeed); + + memset(host->c_cc, 0, sizeof(host->c_cc)); + host->c_cc[VINTR] = target->c_cc[TARGET_VINTR]; + host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT]; + host->c_cc[VERASE] = target->c_cc[TARGET_VERASE]; + host->c_cc[VKILL] = target->c_cc[TARGET_VKILL]; + host->c_cc[VEOF] = target->c_cc[TARGET_VEOF]; + host->c_cc[VTIME] = target->c_cc[TARGET_VTIME]; + host->c_cc[VMIN] = target->c_cc[TARGET_VMIN]; + host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC]; + host->c_cc[VSTART] = target->c_cc[TARGET_VSTART]; + host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP]; + host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP]; + host->c_cc[VEOL] = target->c_cc[TARGET_VEOL]; + host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT]; + host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD]; + host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE]; + host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT]; + host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2]; +} + +static void host_to_target_termios2 (void *dst, const void *src) +{ + struct target_termios2 *target = dst; + const struct host_termios2 *host = src; + + target->c_iflag = + tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl)); + target->c_oflag = + tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl)); + target->c_cflag = + tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl)); + target->c_lflag = + tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl)); + target->c_line = host->c_line; + target->c_ispeed = tswap32(host->c_ispeed); + target->c_ospeed = tswap32(host->c_ospeed); + + memset(target->c_cc, 0, sizeof(target->c_cc)); + target->c_cc[TARGET_VINTR] = host->c_cc[VINTR]; + target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT]; + target->c_cc[TARGET_VERASE] = host->c_cc[VERASE]; + target->c_cc[TARGET_VKILL] = host->c_cc[VKILL]; + target->c_cc[TARGET_VEOF] = host->c_cc[VEOF]; + target->c_cc[TARGET_VTIME] = host->c_cc[VTIME]; + target->c_cc[TARGET_VMIN] = host->c_cc[VMIN]; + target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC]; + target->c_cc[TARGET_VSTART] = host->c_cc[VSTART]; + target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP]; + target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP]; + target->c_cc[TARGET_VEOL] = host->c_cc[VEOL]; + target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT]; + target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD]; + target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE]; + target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT]; + target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2]; +} + +static const StructEntry struct_termios2_def = { + .convert = { host_to_target_termios2, target_to_host_termios2 }, + .size = { sizeof(struct target_termios2), sizeof(struct host_termios2) }, + .align = { __alignof__(struct target_termios2), __alignof__(struct host_termios2) }, + .print = print_termios2, +}; +#endif + /* If the host does not provide these bits, they may be safely discarded. */ #ifndef MAP_SYNC #define MAP_SYNC 0 diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h index 6dd7a80ce5..ac45705acf 100644 --- a/linux-user/syscall_types.h +++ b/linux-user/syscall_types.h @@ -1,4 +1,7 @@ STRUCT_SPECIAL(termios) +#ifdef TARGET_TCGETS2 +STRUCT_SPECIAL(termios2) +#endif STRUCT(winsize, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT) diff --git a/linux-user/user-internals.h b/linux-user/user-internals.h index 7099349ec8..067c02bb93 100644 --- a/linux-user/user-internals.h +++ b/linux-user/user-internals.h @@ -129,6 +129,9 @@ static inline uint64_t target_offset64(uint64_t word0, uint64_t word1) #endif /* TARGET_ABI_BITS != 32 */ void print_termios(void *arg); +#ifdef TARGET_TCGETS2 +void print_termios2(void *arg); +#endif /* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */ #ifdef TARGET_ARM -- 2.50.1
