xref: /qemu/linux-user/semihost.c (revision a10b9d93)
156b5170cSKeith Packard /*
2*a10b9d93SKeith Packard  * ARM Compatible Semihosting Console Support.
356b5170cSKeith Packard  *
456b5170cSKeith Packard  * Copyright (c) 2019 Linaro Ltd
556b5170cSKeith Packard  *
6*a10b9d93SKeith Packard  * Currently ARM and RISC-V are unique in having support for
7*a10b9d93SKeith Packard  * semihosting support in linux-user. So for now we implement the
8*a10b9d93SKeith Packard  * common console API but just for arm and risc-v linux-user.
956b5170cSKeith Packard  *
1056b5170cSKeith Packard  * SPDX-License-Identifier: GPL-2.0-or-later
1156b5170cSKeith Packard  */
1256b5170cSKeith Packard 
1356b5170cSKeith Packard #include "qemu/osdep.h"
1456b5170cSKeith Packard #include "cpu.h"
1556b5170cSKeith Packard #include "hw/semihosting/console.h"
1656b5170cSKeith Packard #include "qemu.h"
1756b5170cSKeith Packard #include <termios.h>
1856b5170cSKeith Packard 
1956b5170cSKeith Packard int qemu_semihosting_console_outs(CPUArchState *env, target_ulong addr)
2056b5170cSKeith Packard {
2156b5170cSKeith Packard     int len = target_strlen(addr);
2256b5170cSKeith Packard     void *s;
2356b5170cSKeith Packard     if (len < 0){
2456b5170cSKeith Packard        qemu_log_mask(LOG_GUEST_ERROR,
2556b5170cSKeith Packard                      "%s: passed inaccessible address " TARGET_FMT_lx,
2656b5170cSKeith Packard                      __func__, addr);
2756b5170cSKeith Packard        return 0;
2856b5170cSKeith Packard     }
2956b5170cSKeith Packard     s = lock_user(VERIFY_READ, addr, (long)(len + 1), 1);
3056b5170cSKeith Packard     g_assert(s);  /* target_strlen has already verified this will work */
3156b5170cSKeith Packard     len = write(STDERR_FILENO, s, len);
3256b5170cSKeith Packard     unlock_user(s, addr, 0);
3356b5170cSKeith Packard     return len;
3456b5170cSKeith Packard }
3556b5170cSKeith Packard 
3656b5170cSKeith Packard void qemu_semihosting_console_outc(CPUArchState *env, target_ulong addr)
3756b5170cSKeith Packard {
3856b5170cSKeith Packard     char c;
3956b5170cSKeith Packard 
4056b5170cSKeith Packard     if (get_user_u8(c, addr)) {
4156b5170cSKeith Packard         qemu_log_mask(LOG_GUEST_ERROR,
4256b5170cSKeith Packard                       "%s: passed inaccessible address " TARGET_FMT_lx,
4356b5170cSKeith Packard                       __func__, addr);
4456b5170cSKeith Packard     } else {
4556b5170cSKeith Packard         if (write(STDERR_FILENO, &c, 1) != 1) {
4656b5170cSKeith Packard             qemu_log_mask(LOG_UNIMP, "%s: unexpected write to stdout failure",
4756b5170cSKeith Packard                           __func__);
4856b5170cSKeith Packard         }
4956b5170cSKeith Packard     }
5056b5170cSKeith Packard }
5156b5170cSKeith Packard 
5256b5170cSKeith Packard /*
5356b5170cSKeith Packard  * For linux-user we can safely block. However as we want to return as
5456b5170cSKeith Packard  * soon as a character is read we need to tweak the termio to disable
5556b5170cSKeith Packard  * line buffering. We restore the old mode afterwards in case the
5656b5170cSKeith Packard  * program is expecting more normal behaviour. This is slow but
5756b5170cSKeith Packard  * nothing using semihosting console reading is expecting to be fast.
5856b5170cSKeith Packard  */
5956b5170cSKeith Packard target_ulong qemu_semihosting_console_inc(CPUArchState *env)
6056b5170cSKeith Packard {
6156b5170cSKeith Packard     uint8_t c;
6256b5170cSKeith Packard     struct termios old_tio, new_tio;
6356b5170cSKeith Packard 
6456b5170cSKeith Packard     /* Disable line-buffering and echo */
6556b5170cSKeith Packard     tcgetattr(STDIN_FILENO, &old_tio);
6656b5170cSKeith Packard     new_tio = old_tio;
6756b5170cSKeith Packard     new_tio.c_lflag &= (~ICANON & ~ECHO);
6856b5170cSKeith Packard     tcsetattr(STDIN_FILENO, TCSANOW, &new_tio);
6956b5170cSKeith Packard 
7056b5170cSKeith Packard     c = getchar();
7156b5170cSKeith Packard 
7256b5170cSKeith Packard     /* restore config */
7356b5170cSKeith Packard     tcsetattr(STDIN_FILENO, TCSANOW, &old_tio);
7456b5170cSKeith Packard 
7556b5170cSKeith Packard     return (target_ulong) c;
7656b5170cSKeith Packard }
77