xref: /openbmc/qemu/linux-user/semihost.c (revision 56b5170c)
1*56b5170cSKeith Packard /*
2*56b5170cSKeith Packard  * ARM Semihosting Console Support
3*56b5170cSKeith Packard  *
4*56b5170cSKeith Packard  * Copyright (c) 2019 Linaro Ltd
5*56b5170cSKeith Packard  *
6*56b5170cSKeith Packard  * Currently ARM is unique in having support for semihosting support
7*56b5170cSKeith Packard  * in linux-user. So for now we implement the common console API but
8*56b5170cSKeith Packard  * just for arm linux-user.
9*56b5170cSKeith Packard  *
10*56b5170cSKeith Packard  * SPDX-License-Identifier: GPL-2.0-or-later
11*56b5170cSKeith Packard  */
12*56b5170cSKeith Packard 
13*56b5170cSKeith Packard #include "qemu/osdep.h"
14*56b5170cSKeith Packard #include "cpu.h"
15*56b5170cSKeith Packard #include "hw/semihosting/console.h"
16*56b5170cSKeith Packard #include "qemu.h"
17*56b5170cSKeith Packard #include <termios.h>
18*56b5170cSKeith Packard 
19*56b5170cSKeith Packard int qemu_semihosting_console_outs(CPUArchState *env, target_ulong addr)
20*56b5170cSKeith Packard {
21*56b5170cSKeith Packard     int len = target_strlen(addr);
22*56b5170cSKeith Packard     void *s;
23*56b5170cSKeith Packard     if (len < 0){
24*56b5170cSKeith Packard        qemu_log_mask(LOG_GUEST_ERROR,
25*56b5170cSKeith Packard                      "%s: passed inaccessible address " TARGET_FMT_lx,
26*56b5170cSKeith Packard                      __func__, addr);
27*56b5170cSKeith Packard        return 0;
28*56b5170cSKeith Packard     }
29*56b5170cSKeith Packard     s = lock_user(VERIFY_READ, addr, (long)(len + 1), 1);
30*56b5170cSKeith Packard     g_assert(s);  /* target_strlen has already verified this will work */
31*56b5170cSKeith Packard     len = write(STDERR_FILENO, s, len);
32*56b5170cSKeith Packard     unlock_user(s, addr, 0);
33*56b5170cSKeith Packard     return len;
34*56b5170cSKeith Packard }
35*56b5170cSKeith Packard 
36*56b5170cSKeith Packard void qemu_semihosting_console_outc(CPUArchState *env, target_ulong addr)
37*56b5170cSKeith Packard {
38*56b5170cSKeith Packard     char c;
39*56b5170cSKeith Packard 
40*56b5170cSKeith Packard     if (get_user_u8(c, addr)) {
41*56b5170cSKeith Packard         qemu_log_mask(LOG_GUEST_ERROR,
42*56b5170cSKeith Packard                       "%s: passed inaccessible address " TARGET_FMT_lx,
43*56b5170cSKeith Packard                       __func__, addr);
44*56b5170cSKeith Packard     } else {
45*56b5170cSKeith Packard         if (write(STDERR_FILENO, &c, 1) != 1) {
46*56b5170cSKeith Packard             qemu_log_mask(LOG_UNIMP, "%s: unexpected write to stdout failure",
47*56b5170cSKeith Packard                           __func__);
48*56b5170cSKeith Packard         }
49*56b5170cSKeith Packard     }
50*56b5170cSKeith Packard }
51*56b5170cSKeith Packard 
52*56b5170cSKeith Packard /*
53*56b5170cSKeith Packard  * For linux-user we can safely block. However as we want to return as
54*56b5170cSKeith Packard  * soon as a character is read we need to tweak the termio to disable
55*56b5170cSKeith Packard  * line buffering. We restore the old mode afterwards in case the
56*56b5170cSKeith Packard  * program is expecting more normal behaviour. This is slow but
57*56b5170cSKeith Packard  * nothing using semihosting console reading is expecting to be fast.
58*56b5170cSKeith Packard  */
59*56b5170cSKeith Packard target_ulong qemu_semihosting_console_inc(CPUArchState *env)
60*56b5170cSKeith Packard {
61*56b5170cSKeith Packard     uint8_t c;
62*56b5170cSKeith Packard     struct termios old_tio, new_tio;
63*56b5170cSKeith Packard 
64*56b5170cSKeith Packard     /* Disable line-buffering and echo */
65*56b5170cSKeith Packard     tcgetattr(STDIN_FILENO, &old_tio);
66*56b5170cSKeith Packard     new_tio = old_tio;
67*56b5170cSKeith Packard     new_tio.c_lflag &= (~ICANON & ~ECHO);
68*56b5170cSKeith Packard     tcsetattr(STDIN_FILENO, TCSANOW, &new_tio);
69*56b5170cSKeith Packard 
70*56b5170cSKeith Packard     c = getchar();
71*56b5170cSKeith Packard 
72*56b5170cSKeith Packard     /* restore config */
73*56b5170cSKeith Packard     tcsetattr(STDIN_FILENO, TCSANOW, &old_tio);
74*56b5170cSKeith Packard 
75*56b5170cSKeith Packard     return (target_ulong) c;
76*56b5170cSKeith Packard }
77