xref: /openbmc/qemu/semihosting/console.c (revision 9468484fe904ab4691de6d9c34616667f377ceac)
18df9f0c3SPhilippe Mathieu-Daudé /*
28df9f0c3SPhilippe Mathieu-Daudé  * Semihosting Console Support
38df9f0c3SPhilippe Mathieu-Daudé  *
48df9f0c3SPhilippe Mathieu-Daudé  * Copyright (c) 2015 Imagination Technologies
58df9f0c3SPhilippe Mathieu-Daudé  * Copyright (c) 2019 Linaro Ltd
68df9f0c3SPhilippe Mathieu-Daudé  *
78df9f0c3SPhilippe Mathieu-Daudé  * This provides support for outputting to a semihosting console.
88df9f0c3SPhilippe Mathieu-Daudé  *
98df9f0c3SPhilippe Mathieu-Daudé  * While most semihosting implementations support reading and writing
108df9f0c3SPhilippe Mathieu-Daudé  * to arbitrary file descriptors we treat the console as something
118df9f0c3SPhilippe Mathieu-Daudé  * specifically for debugging interaction. This means messages can be
128df9f0c3SPhilippe Mathieu-Daudé  * re-directed to gdb (if currently being used to debug) or even
138df9f0c3SPhilippe Mathieu-Daudé  * re-directed elsewhere.
148df9f0c3SPhilippe Mathieu-Daudé  *
158df9f0c3SPhilippe Mathieu-Daudé  * SPDX-License-Identifier: GPL-2.0-or-later
168df9f0c3SPhilippe Mathieu-Daudé  */
178df9f0c3SPhilippe Mathieu-Daudé 
188df9f0c3SPhilippe Mathieu-Daudé #include "qemu/osdep.h"
198df9f0c3SPhilippe Mathieu-Daudé #include "semihosting/semihost.h"
208df9f0c3SPhilippe Mathieu-Daudé #include "semihosting/console.h"
218df9f0c3SPhilippe Mathieu-Daudé #include "exec/gdbstub.h"
228df9f0c3SPhilippe Mathieu-Daudé #include "exec/exec-all.h"
238df9f0c3SPhilippe Mathieu-Daudé #include "qemu/log.h"
248df9f0c3SPhilippe Mathieu-Daudé #include "chardev/char.h"
258df9f0c3SPhilippe Mathieu-Daudé #include "chardev/char-fe.h"
268df9f0c3SPhilippe Mathieu-Daudé #include "qemu/main-loop.h"
278df9f0c3SPhilippe Mathieu-Daudé #include "qapi/error.h"
288df9f0c3SPhilippe Mathieu-Daudé #include "qemu/fifo8.h"
298df9f0c3SPhilippe Mathieu-Daudé 
30fb08790bSRichard Henderson /* Access to this structure is protected by the BQL */
31fb08790bSRichard Henderson typedef struct SemihostingConsole {
32fb08790bSRichard Henderson     CharBackend         backend;
33fb08790bSRichard Henderson     Chardev             *chr;
34fb08790bSRichard Henderson     GSList              *sleeping_cpus;
35fb08790bSRichard Henderson     bool                got;
36fb08790bSRichard Henderson     Fifo8               fifo;
37fb08790bSRichard Henderson } SemihostingConsole;
38fb08790bSRichard Henderson 
39fb08790bSRichard Henderson static SemihostingConsole console;
40fb08790bSRichard Henderson 
418df9f0c3SPhilippe Mathieu-Daudé #define FIFO_SIZE   1024
428df9f0c3SPhilippe Mathieu-Daudé 
console_can_read(void * opaque)438df9f0c3SPhilippe Mathieu-Daudé static int console_can_read(void *opaque)
448df9f0c3SPhilippe Mathieu-Daudé {
458df9f0c3SPhilippe Mathieu-Daudé     SemihostingConsole *c = opaque;
46*195801d7SStefan Hajnoczi     g_assert(bql_locked());
4766997c42SMarkus Armbruster     return (int)fifo8_num_free(&c->fifo);
488df9f0c3SPhilippe Mathieu-Daudé }
498df9f0c3SPhilippe Mathieu-Daudé 
console_wake_up(gpointer data,gpointer user_data)508df9f0c3SPhilippe Mathieu-Daudé static void console_wake_up(gpointer data, gpointer user_data)
518df9f0c3SPhilippe Mathieu-Daudé {
528df9f0c3SPhilippe Mathieu-Daudé     CPUState *cs = (CPUState *) data;
538df9f0c3SPhilippe Mathieu-Daudé     /* cpu_handle_halt won't know we have work so just unbung here */
548df9f0c3SPhilippe Mathieu-Daudé     cs->halted = 0;
558df9f0c3SPhilippe Mathieu-Daudé     qemu_cpu_kick(cs);
568df9f0c3SPhilippe Mathieu-Daudé }
578df9f0c3SPhilippe Mathieu-Daudé 
console_read(void * opaque,const uint8_t * buf,int size)588df9f0c3SPhilippe Mathieu-Daudé static void console_read(void *opaque, const uint8_t *buf, int size)
598df9f0c3SPhilippe Mathieu-Daudé {
608df9f0c3SPhilippe Mathieu-Daudé     SemihostingConsole *c = opaque;
61*195801d7SStefan Hajnoczi     g_assert(bql_locked());
628df9f0c3SPhilippe Mathieu-Daudé     while (size-- && !fifo8_is_full(&c->fifo)) {
638df9f0c3SPhilippe Mathieu-Daudé         fifo8_push(&c->fifo, *buf++);
648df9f0c3SPhilippe Mathieu-Daudé     }
658df9f0c3SPhilippe Mathieu-Daudé     g_slist_foreach(c->sleeping_cpus, console_wake_up, NULL);
668df9f0c3SPhilippe Mathieu-Daudé     c->sleeping_cpus = NULL;
678df9f0c3SPhilippe Mathieu-Daudé }
688df9f0c3SPhilippe Mathieu-Daudé 
qemu_semihosting_console_ready(void)691b9177f7SRichard Henderson bool qemu_semihosting_console_ready(void)
708df9f0c3SPhilippe Mathieu-Daudé {
718df9f0c3SPhilippe Mathieu-Daudé     SemihostingConsole *c = &console;
721b9177f7SRichard Henderson 
73*195801d7SStefan Hajnoczi     g_assert(bql_locked());
741b9177f7SRichard Henderson     return !fifo8_is_empty(&c->fifo);
751b9177f7SRichard Henderson }
761b9177f7SRichard Henderson 
qemu_semihosting_console_block_until_ready(CPUState * cs)771b9177f7SRichard Henderson void qemu_semihosting_console_block_until_ready(CPUState *cs)
781b9177f7SRichard Henderson {
791b9177f7SRichard Henderson     SemihostingConsole *c = &console;
803367d452SRichard Henderson 
81*195801d7SStefan Hajnoczi     g_assert(bql_locked());
82e7fb6f32SRichard Henderson 
83e7fb6f32SRichard Henderson     /* Block if the fifo is completely empty. */
848df9f0c3SPhilippe Mathieu-Daudé     if (fifo8_is_empty(&c->fifo)) {
853367d452SRichard Henderson         c->sleeping_cpus = g_slist_prepend(c->sleeping_cpus, cs);
863367d452SRichard Henderson         cs->halted = 1;
873367d452SRichard Henderson         cs->exception_index = EXCP_HALTED;
883367d452SRichard Henderson         cpu_loop_exit(cs);
898df9f0c3SPhilippe Mathieu-Daudé         /* never returns */
908df9f0c3SPhilippe Mathieu-Daudé     }
911b9177f7SRichard Henderson }
921b9177f7SRichard Henderson 
qemu_semihosting_console_read(CPUState * cs,void * buf,int len)931b9177f7SRichard Henderson int qemu_semihosting_console_read(CPUState *cs, void *buf, int len)
941b9177f7SRichard Henderson {
951b9177f7SRichard Henderson     SemihostingConsole *c = &console;
961b9177f7SRichard Henderson     int ret = 0;
971b9177f7SRichard Henderson 
981b9177f7SRichard Henderson     qemu_semihosting_console_block_until_ready(cs);
99e7fb6f32SRichard Henderson 
100e7fb6f32SRichard Henderson     /* Read until buffer full or fifo exhausted. */
101e7fb6f32SRichard Henderson     do {
102e7fb6f32SRichard Henderson         *(char *)(buf + ret) = fifo8_pop(&c->fifo);
103e7fb6f32SRichard Henderson         ret++;
104e7fb6f32SRichard Henderson     } while (ret < len && !fifo8_is_empty(&c->fifo));
105e7fb6f32SRichard Henderson 
106e7fb6f32SRichard Henderson     return ret;
1078df9f0c3SPhilippe Mathieu-Daudé }
1088df9f0c3SPhilippe Mathieu-Daudé 
qemu_semihosting_console_write(void * buf,int len)109cd66f20fSRichard Henderson int qemu_semihosting_console_write(void *buf, int len)
110cd66f20fSRichard Henderson {
111cd66f20fSRichard Henderson     if (console.chr) {
112aed04e63SPeter Maydell         int r = qemu_chr_write_all(console.chr, (uint8_t *)buf, len);
113aed04e63SPeter Maydell         return r < 0 ? 0 : r;
114cd66f20fSRichard Henderson     } else {
115cd66f20fSRichard Henderson         return fwrite(buf, 1, len, stderr);
116cd66f20fSRichard Henderson     }
117cd66f20fSRichard Henderson }
118cd66f20fSRichard Henderson 
qemu_semihosting_console_init(Chardev * chr)119fb08790bSRichard Henderson void qemu_semihosting_console_init(Chardev *chr)
1208df9f0c3SPhilippe Mathieu-Daudé {
121fb08790bSRichard Henderson     console.chr = chr;
1228df9f0c3SPhilippe Mathieu-Daudé     if  (chr) {
1238df9f0c3SPhilippe Mathieu-Daudé         fifo8_create(&console.fifo, FIFO_SIZE);
1248df9f0c3SPhilippe Mathieu-Daudé         qemu_chr_fe_init(&console.backend, chr, &error_abort);
1258df9f0c3SPhilippe Mathieu-Daudé         qemu_chr_fe_set_handlers(&console.backend,
1268df9f0c3SPhilippe Mathieu-Daudé                                  console_can_read,
1278df9f0c3SPhilippe Mathieu-Daudé                                  console_read,
1288df9f0c3SPhilippe Mathieu-Daudé                                  NULL, NULL, &console,
1298df9f0c3SPhilippe Mathieu-Daudé                                  NULL, true);
1308df9f0c3SPhilippe Mathieu-Daudé     }
131e4a4aaa5SRichard Henderson 
132e4a4aaa5SRichard Henderson     qemu_semihosting_guestfd_init();
1338df9f0c3SPhilippe Mathieu-Daudé }
134