2 * Semihosting Console Support
4 * Copyright (c) 2015 Imagination Technologies
5 * Copyright (c) 2019 Linaro Ltd
7 * This provides support for outputting to a semihosting console.
9 * While most semihosting implementations support reading and writing
10 * to arbitrary file descriptors we treat the console as something
11 * specifically for debugging interaction. This means messages can be
12 * re-directed to gdb (if currently being used to debug) or even
13 * re-directed elsewhere.
15 * SPDX-License-Identifier: GPL-2.0-or-later
18 #include "qemu/osdep.h"
19 #include "semihosting/semihost.h"
20 #include "semihosting/console.h"
21 #include "exec/gdbstub.h"
22 #include "exec/exec-all.h"
24 #include "chardev/char.h"
25 #include "chardev/char-fe.h"
26 #include "qemu/main-loop.h"
27 #include "qapi/error.h"
28 #include "qemu/fifo8.h"
30 /* Access to this structure is protected by the BQL */
31 typedef struct SemihostingConsole
{
34 GSList
*sleeping_cpus
;
39 static SemihostingConsole console
;
41 int qemu_semihosting_log_out(const char *s
, int len
)
44 return qemu_chr_write_all(console
.chr
, (uint8_t *) s
, len
);
46 return write(STDERR_FILENO
, s
, len
);
50 #define FIFO_SIZE 1024
52 static int console_can_read(void *opaque
)
54 SemihostingConsole
*c
= opaque
;
56 g_assert(qemu_mutex_iothread_locked());
57 ret
= (int) fifo8_num_free(&c
->fifo
);
61 static void console_wake_up(gpointer data
, gpointer user_data
)
63 CPUState
*cs
= (CPUState
*) data
;
64 /* cpu_handle_halt won't know we have work so just unbung here */
69 static void console_read(void *opaque
, const uint8_t *buf
, int size
)
71 SemihostingConsole
*c
= opaque
;
72 g_assert(qemu_mutex_iothread_locked());
73 while (size
-- && !fifo8_is_full(&c
->fifo
)) {
74 fifo8_push(&c
->fifo
, *buf
++);
76 g_slist_foreach(c
->sleeping_cpus
, console_wake_up
, NULL
);
77 c
->sleeping_cpus
= NULL
;
80 bool qemu_semihosting_console_ready(void)
82 SemihostingConsole
*c
= &console
;
84 g_assert(qemu_mutex_iothread_locked());
85 return !fifo8_is_empty(&c
->fifo
);
88 void qemu_semihosting_console_block_until_ready(CPUState
*cs
)
90 SemihostingConsole
*c
= &console
;
92 g_assert(qemu_mutex_iothread_locked());
94 /* Block if the fifo is completely empty. */
95 if (fifo8_is_empty(&c
->fifo
)) {
96 c
->sleeping_cpus
= g_slist_prepend(c
->sleeping_cpus
, cs
);
98 cs
->exception_index
= EXCP_HALTED
;
104 int qemu_semihosting_console_read(CPUState
*cs
, void *buf
, int len
)
106 SemihostingConsole
*c
= &console
;
109 qemu_semihosting_console_block_until_ready(cs
);
111 /* Read until buffer full or fifo exhausted. */
113 *(char *)(buf
+ ret
) = fifo8_pop(&c
->fifo
);
115 } while (ret
< len
&& !fifo8_is_empty(&c
->fifo
));
120 int qemu_semihosting_console_write(void *buf
, int len
)
123 return qemu_chr_write_all(console
.chr
, (uint8_t *)buf
, len
);
125 return fwrite(buf
, 1, len
, stderr
);
129 void qemu_semihosting_console_init(Chardev
*chr
)
133 fifo8_create(&console
.fifo
, FIFO_SIZE
);
134 qemu_chr_fe_init(&console
.backend
, chr
, &error_abort
);
135 qemu_chr_fe_set_handlers(&console
.backend
,
138 NULL
, NULL
, &console
,
142 qemu_semihosting_guestfd_init();