diff mbox series

target/xtensa: support input from chardev console

Message ID 20180909022104.5939-1-jcmvbkbc@gmail.com (mailing list archive)
State New, archived
Headers show
Series target/xtensa: support input from chardev console | expand

Commit Message

Max Filippov Sept. 9, 2018, 2:21 a.m. UTC
Complete xtensa-semi chardev console implementation: allow reading input
characters from file descriptor 0 and call sys_select_one simcall on it.

Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
---
 target/xtensa/xtensa-semi.c | 55 ++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 52 insertions(+), 3 deletions(-)
diff mbox series

Patch

diff --git a/target/xtensa/xtensa-semi.c b/target/xtensa/xtensa-semi.c
index 7aa1d1357bda..f3c23f8625c2 100644
--- a/target/xtensa/xtensa-semi.c
+++ b/target/xtensa/xtensa-semi.c
@@ -34,8 +34,6 @@ 
 #include "qemu/log.h"
 #include "sysemu/sysemu.h"
 
-static CharBackend *xtensa_sim_console;
-
 enum {
     TARGET_SYS_exit = 1,
     TARGET_SYS_read = 3,
@@ -153,12 +151,45 @@  static uint32_t errno_h2g(int host_errno)
     }
 }
 
+typedef struct SimInputBuffer {
+    char buffer[16];
+    size_t offset;
+} SimInputBuffer;
+
+static CharBackend *xtensa_sim_console;
+static SimInputBuffer sim_input_buffer;
+
+static IOCanReadHandler xtensa_sim_console_can_read;
+static int xtensa_sim_console_can_read(void *opaque)
+{
+    SimInputBuffer *p = opaque;
+
+    return sizeof(p->buffer) - p->offset;
+}
+
+static IOReadHandler xtensa_sim_console_read;
+static void xtensa_sim_console_read(void *opaque, const uint8_t *buf, int size)
+{
+    SimInputBuffer *p = opaque;
+    size_t copy = sizeof(p->buffer) - p->offset;
+
+    if (size < copy) {
+        copy = size;
+    }
+    memcpy(p->buffer + p->offset, buf, copy);
+    p->offset += copy;
+}
+
 void xtensa_sim_open_console(Chardev *chr)
 {
     static CharBackend console;
 
     qemu_chr_fe_init(&console, chr, &error_abort);
-    qemu_chr_fe_set_handlers(&console, NULL, NULL, NULL, NULL, NULL, NULL, true);
+    qemu_chr_fe_set_handlers(&console,
+                             xtensa_sim_console_can_read,
+                             xtensa_sim_console_read,
+                             NULL, NULL, &sim_input_buffer,
+                             NULL, true);
     xtensa_sim_console = &console;
 }
 
@@ -200,6 +231,22 @@  void HELPER(simcall)(CPUXtensaState *env)
                             io_done = qemu_chr_fe_write_all(xtensa_sim_console,
                                                             buf, io_sz);
                             regs[3] = errno_h2g(errno);
+                        } else if (!is_write && fd == 0) {
+                            if (sim_input_buffer.offset) {
+                                io_done = sim_input_buffer.offset;
+                                if (io_sz < io_done) {
+                                    io_done = io_sz;
+                                }
+                                memcpy(buf, sim_input_buffer.buffer, io_done);
+                                memmove(sim_input_buffer.buffer,
+                                        sim_input_buffer.buffer + io_done,
+                                        sim_input_buffer.offset - io_done);
+                                sim_input_buffer.offset -= io_done;
+                                qemu_chr_fe_accept_input(xtensa_sim_console);
+                            } else {
+                                io_done = -1;
+                                regs[3] = TARGET_EAGAIN;
+                            }
                         } else {
                             qemu_log_mask(LOG_GUEST_ERROR,
                                           "%s fd %d is not supported with chardev console\n",
@@ -295,6 +342,8 @@  void HELPER(simcall)(CPUXtensaState *env)
             if (fd < 3 && xtensa_sim_console) {
                 if ((fd == 1 || fd == 2) && rq == SELECT_ONE_WRITE) {
                     regs[2] = 1;
+                } else if (fd == 0 && rq == SELECT_ONE_READ) {
+                    regs[2] = sim_input_buffer.offset > 0;
                 } else {
                     regs[2] = 0;
                 }