qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

console.c (3653B)


      1 /*
      2  * Semihosting Console Support
      3  *
      4  * Copyright (c) 2015 Imagination Technologies
      5  * Copyright (c) 2019 Linaro Ltd
      6  *
      7  * This provides support for outputting to a semihosting console.
      8  *
      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.
     14  *
     15  * SPDX-License-Identifier: GPL-2.0-or-later
     16  */
     17 
     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"
     23 #include "qemu/log.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"
     29 
     30 /* Access to this structure is protected by the BQL */
     31 typedef struct SemihostingConsole {
     32     CharBackend         backend;
     33     Chardev             *chr;
     34     GSList              *sleeping_cpus;
     35     bool                got;
     36     Fifo8               fifo;
     37 } SemihostingConsole;
     38 
     39 static SemihostingConsole console;
     40 
     41 #define FIFO_SIZE   1024
     42 
     43 static int console_can_read(void *opaque)
     44 {
     45     SemihostingConsole *c = opaque;
     46     int ret;
     47     g_assert(qemu_mutex_iothread_locked());
     48     ret = (int) fifo8_num_free(&c->fifo);
     49     return ret;
     50 }
     51 
     52 static void console_wake_up(gpointer data, gpointer user_data)
     53 {
     54     CPUState *cs = (CPUState *) data;
     55     /* cpu_handle_halt won't know we have work so just unbung here */
     56     cs->halted = 0;
     57     qemu_cpu_kick(cs);
     58 }
     59 
     60 static void console_read(void *opaque, const uint8_t *buf, int size)
     61 {
     62     SemihostingConsole *c = opaque;
     63     g_assert(qemu_mutex_iothread_locked());
     64     while (size-- && !fifo8_is_full(&c->fifo)) {
     65         fifo8_push(&c->fifo, *buf++);
     66     }
     67     g_slist_foreach(c->sleeping_cpus, console_wake_up, NULL);
     68     c->sleeping_cpus = NULL;
     69 }
     70 
     71 bool qemu_semihosting_console_ready(void)
     72 {
     73     SemihostingConsole *c = &console;
     74 
     75     g_assert(qemu_mutex_iothread_locked());
     76     return !fifo8_is_empty(&c->fifo);
     77 }
     78 
     79 void qemu_semihosting_console_block_until_ready(CPUState *cs)
     80 {
     81     SemihostingConsole *c = &console;
     82 
     83     g_assert(qemu_mutex_iothread_locked());
     84 
     85     /* Block if the fifo is completely empty. */
     86     if (fifo8_is_empty(&c->fifo)) {
     87         c->sleeping_cpus = g_slist_prepend(c->sleeping_cpus, cs);
     88         cs->halted = 1;
     89         cs->exception_index = EXCP_HALTED;
     90         cpu_loop_exit(cs);
     91         /* never returns */
     92     }
     93 }
     94 
     95 int qemu_semihosting_console_read(CPUState *cs, void *buf, int len)
     96 {
     97     SemihostingConsole *c = &console;
     98     int ret = 0;
     99 
    100     qemu_semihosting_console_block_until_ready(cs);
    101 
    102     /* Read until buffer full or fifo exhausted. */
    103     do {
    104         *(char *)(buf + ret) = fifo8_pop(&c->fifo);
    105         ret++;
    106     } while (ret < len && !fifo8_is_empty(&c->fifo));
    107 
    108     return ret;
    109 }
    110 
    111 int qemu_semihosting_console_write(void *buf, int len)
    112 {
    113     if (console.chr) {
    114         int r = qemu_chr_write_all(console.chr, (uint8_t *)buf, len);
    115         return r < 0 ? 0 : r;
    116     } else {
    117         return fwrite(buf, 1, len, stderr);
    118     }
    119 }
    120 
    121 void qemu_semihosting_console_init(Chardev *chr)
    122 {
    123     console.chr = chr;
    124     if  (chr) {
    125         fifo8_create(&console.fifo, FIFO_SIZE);
    126         qemu_chr_fe_init(&console.backend, chr, &error_abort);
    127         qemu_chr_fe_set_handlers(&console.backend,
    128                                  console_can_read,
    129                                  console_read,
    130                                  NULL, NULL, &console,
    131                                  NULL, true);
    132     }
    133 
    134     qemu_semihosting_guestfd_init();
    135 }