diff mbox series

[v4,53/53] semihosting: Create semihost_sys_poll_one

Message ID 20220607204557.658541-54-richard.henderson@linaro.org
State Superseded
Headers show
Series semihosting cleanup | expand

Commit Message

Richard Henderson June 7, 2022, 8:45 p.m. UTC
This will be used for implementing the xtensa select_one
system call.  Choose "poll" over "select" so that we can
reuse Glib's g_poll constants and to avoid struct timeval.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/semihosting/console.h  | 16 ++++++++
 include/semihosting/syscalls.h |  3 ++
 semihosting/console.c          | 19 ++++++++-
 semihosting/syscalls.c         | 70 ++++++++++++++++++++++++++++++++++
 4 files changed, 106 insertions(+), 2 deletions(-)

Comments

Luc Michel June 27, 2022, 9:01 a.m. UTC | #1
On 13:45 Tue 07 Jun     , Richard Henderson wrote:
> This will be used for implementing the xtensa select_one
> system call.  Choose "poll" over "select" so that we can
> reuse Glib's g_poll constants and to avoid struct timeval.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

Reviewed-by: Luc Michel <lmichel@kalray.eu>

> ---
>  include/semihosting/console.h  | 16 ++++++++
>  include/semihosting/syscalls.h |  3 ++
>  semihosting/console.c          | 19 ++++++++-
>  semihosting/syscalls.c         | 70 ++++++++++++++++++++++++++++++++++
>  4 files changed, 106 insertions(+), 2 deletions(-)
> 
> diff --git a/include/semihosting/console.h b/include/semihosting/console.h
> index 20c31d89d4..61b0cb3a94 100644
> --- a/include/semihosting/console.h
> +++ b/include/semihosting/console.h
> @@ -53,4 +53,20 @@ int qemu_semihosting_console_write(void *buf, int len);
>   */
>  int qemu_semihosting_log_out(const char *s, int len);
>  
> +/*
> + * qemu_semihosting_console_block_until_ready:
> + * @cs: CPUState
> + *
> + * If no data is available we suspend the CPU and will re-execute the
> + * instruction when data is available.
> + */
> +void qemu_semihosting_console_block_until_ready(CPUState *cs);
> +
> +/**
> + * qemu_semihosting_console_ready:
> + *
> + * Return true if characters are available for read; does not block.
> + */
> +bool qemu_semihosting_console_ready(void);
> +
>  #endif /* SEMIHOST_CONSOLE_H */
> diff --git a/include/semihosting/syscalls.h b/include/semihosting/syscalls.h
> index 347200cb9f..3a5ec229eb 100644
> --- a/include/semihosting/syscalls.h
> +++ b/include/semihosting/syscalls.h
> @@ -69,4 +69,7 @@ void semihost_sys_system(CPUState *cs, gdb_syscall_complete_cb complete,
>  void semihost_sys_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete,
>                                 target_ulong tv_addr, target_ulong tz_addr);
>  
> +void semihost_sys_poll_one(CPUState *cs, gdb_syscall_complete_cb complete,
> +                           int fd, GIOCondition cond, int timeout);
> +
>  #endif /* SEMIHOSTING_SYSCALLS_H */
> diff --git a/semihosting/console.c b/semihosting/console.c
> index c84ab97ab6..cda7cf1905 100644
> --- a/semihosting/console.c
> +++ b/semihosting/console.c
> @@ -77,10 +77,17 @@ static void console_read(void *opaque, const uint8_t *buf, int size)
>      c->sleeping_cpus = NULL;
>  }
>  
> -int qemu_semihosting_console_read(CPUState *cs, void *buf, int len)
> +bool qemu_semihosting_console_ready(void)
> +{
> +    SemihostingConsole *c = &console;
> +
> +    g_assert(qemu_mutex_iothread_locked());
> +    return !fifo8_is_empty(&c->fifo);
> +}
> +
> +void qemu_semihosting_console_block_until_ready(CPUState *cs)
>  {
>      SemihostingConsole *c = &console;
> -    int ret = 0;
>  
>      g_assert(qemu_mutex_iothread_locked());
>  
> @@ -92,6 +99,14 @@ int qemu_semihosting_console_read(CPUState *cs, void *buf, int len)
>          cpu_loop_exit(cs);
>          /* never returns */
>      }
> +}
> +
> +int qemu_semihosting_console_read(CPUState *cs, void *buf, int len)
> +{
> +    SemihostingConsole *c = &console;
> +    int ret = 0;
> +
> +    qemu_semihosting_console_block_until_ready(cs);
>  
>      /* Read until buffer full or fifo exhausted. */
>      do {
> diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c
> index 9e499b1751..4847f66c02 100644
> --- a/semihosting/syscalls.c
> +++ b/semihosting/syscalls.c
> @@ -520,6 +520,21 @@ static void host_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete,
>      unlock_user(p, tv_addr, sizeof(struct gdb_timeval));
>  }
>  
> +#ifndef CONFIG_USER_ONLY
> +static void host_poll_one(CPUState *cs, gdb_syscall_complete_cb complete,
> +                          GuestFD *gf, GIOCondition cond, int timeout)
> +{
> +    /*
> +     * Since this is only used by xtensa in system mode, and stdio is
> +     * handled through GuestFDConsole, and there are no semihosting
> +     * system calls for sockets and the like, that means this descriptor
> +     * must be a normal file.  Normal files never block and are thus
> +     * always ready.
> +     */
> +    complete(cs, cond & (G_IO_IN | G_IO_OUT), 0);
> +}
> +#endif
> +
>  /*
>   * Static file semihosting syscall implementations.
>   */
> @@ -628,6 +643,34 @@ static void console_fstat(CPUState *cs, gdb_syscall_complete_cb complete,
>      complete(cs, ret ? -1 : 0, ret ? -ret : 0);
>  }
>  
> +#ifndef CONFIG_USER_ONLY
> +static void console_poll_one(CPUState *cs, gdb_syscall_complete_cb complete,
> +                             GuestFD *gf, GIOCondition cond, int timeout)
> +{
> +    /* The semihosting console does not support urgent data or errors. */
> +    cond &= G_IO_IN | G_IO_OUT;
> +
> +    /*
> +     * Since qemu_semihosting_console_write never blocks, we can
> +     * consider output always ready -- leave G_IO_OUT alone.
> +     * All that remains is to conditionally signal input ready.
> +     * Since output ready causes an immediate return, only block
> +     * for G_IO_IN alone.
> +     *
> +     * TODO: Implement proper timeout.  For now, only support
> +     * indefinite wait or immediate poll.
> +     */
> +    if (cond == G_IO_IN && timeout < 0) {
> +        qemu_semihosting_console_block_until_ready(cs);
> +        /* We returned -- input must be ready. */
> +    } else if ((cond & G_IO_IN) && !qemu_semihosting_console_ready()) {
> +        cond &= ~G_IO_IN;
> +    }
> +
> +    complete(cs, cond, 0);
> +}
> +#endif
> +
>  /*
>   * Syscall entry points.
>   */
> @@ -906,3 +949,30 @@ void semihost_sys_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete,
>          host_gettimeofday(cs, complete, tv_addr, tz_addr);
>      }
>  }
> +
> +#ifndef CONFIG_USER_ONLY
> +void semihost_sys_poll_one(CPUState *cs, gdb_syscall_complete_cb complete,
> +                           int fd, GIOCondition cond, int timeout)
> +{
> +    GuestFD *gf = get_guestfd(fd);
> +
> +    if (!gf) {
> +        complete(cs, G_IO_NVAL, 1);
> +        return;
> +    }
> +    switch (gf->type) {
> +    case GuestFDGDB:
> +        complete(cs, G_IO_NVAL, 1);
> +        break;
> +    case GuestFDHost:
> +        host_poll_one(cs, complete, gf, cond, timeout);
> +        break;
> +    case GuestFDConsole:
> +        console_poll_one(cs, complete, gf, cond, timeout);
> +        break;
> +    case GuestFDStatic:
> +    default:
> +        g_assert_not_reached();
> +    }
> +}
> +#endif
> -- 
> 2.34.1
> 
> 
> 
> 
> To declare a filtering error, please use the following link : https://www.security-mail.net/reporter.php?mid=10175.629fd339.9c340.0&r=lmichel%40kalrayinc.com&s=qemu-devel-bounces%2Blmichel%3Dkalrayinc.com%40nongnu.org&o=%5BPATCH+v4+53%2F53%5D+semihosting%3A+Create+semihost_sys_poll_one&verdict=C&c=0a7b4120e6d77de407da84480eecf3246fb89c81
> 

--
diff mbox series

Patch

diff --git a/include/semihosting/console.h b/include/semihosting/console.h
index 20c31d89d4..61b0cb3a94 100644
--- a/include/semihosting/console.h
+++ b/include/semihosting/console.h
@@ -53,4 +53,20 @@  int qemu_semihosting_console_write(void *buf, int len);
  */
 int qemu_semihosting_log_out(const char *s, int len);
 
+/*
+ * qemu_semihosting_console_block_until_ready:
+ * @cs: CPUState
+ *
+ * If no data is available we suspend the CPU and will re-execute the
+ * instruction when data is available.
+ */
+void qemu_semihosting_console_block_until_ready(CPUState *cs);
+
+/**
+ * qemu_semihosting_console_ready:
+ *
+ * Return true if characters are available for read; does not block.
+ */
+bool qemu_semihosting_console_ready(void);
+
 #endif /* SEMIHOST_CONSOLE_H */
diff --git a/include/semihosting/syscalls.h b/include/semihosting/syscalls.h
index 347200cb9f..3a5ec229eb 100644
--- a/include/semihosting/syscalls.h
+++ b/include/semihosting/syscalls.h
@@ -69,4 +69,7 @@  void semihost_sys_system(CPUState *cs, gdb_syscall_complete_cb complete,
 void semihost_sys_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete,
                                target_ulong tv_addr, target_ulong tz_addr);
 
+void semihost_sys_poll_one(CPUState *cs, gdb_syscall_complete_cb complete,
+                           int fd, GIOCondition cond, int timeout);
+
 #endif /* SEMIHOSTING_SYSCALLS_H */
diff --git a/semihosting/console.c b/semihosting/console.c
index c84ab97ab6..cda7cf1905 100644
--- a/semihosting/console.c
+++ b/semihosting/console.c
@@ -77,10 +77,17 @@  static void console_read(void *opaque, const uint8_t *buf, int size)
     c->sleeping_cpus = NULL;
 }
 
-int qemu_semihosting_console_read(CPUState *cs, void *buf, int len)
+bool qemu_semihosting_console_ready(void)
+{
+    SemihostingConsole *c = &console;
+
+    g_assert(qemu_mutex_iothread_locked());
+    return !fifo8_is_empty(&c->fifo);
+}
+
+void qemu_semihosting_console_block_until_ready(CPUState *cs)
 {
     SemihostingConsole *c = &console;
-    int ret = 0;
 
     g_assert(qemu_mutex_iothread_locked());
 
@@ -92,6 +99,14 @@  int qemu_semihosting_console_read(CPUState *cs, void *buf, int len)
         cpu_loop_exit(cs);
         /* never returns */
     }
+}
+
+int qemu_semihosting_console_read(CPUState *cs, void *buf, int len)
+{
+    SemihostingConsole *c = &console;
+    int ret = 0;
+
+    qemu_semihosting_console_block_until_ready(cs);
 
     /* Read until buffer full or fifo exhausted. */
     do {
diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c
index 9e499b1751..4847f66c02 100644
--- a/semihosting/syscalls.c
+++ b/semihosting/syscalls.c
@@ -520,6 +520,21 @@  static void host_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete,
     unlock_user(p, tv_addr, sizeof(struct gdb_timeval));
 }
 
+#ifndef CONFIG_USER_ONLY
+static void host_poll_one(CPUState *cs, gdb_syscall_complete_cb complete,
+                          GuestFD *gf, GIOCondition cond, int timeout)
+{
+    /*
+     * Since this is only used by xtensa in system mode, and stdio is
+     * handled through GuestFDConsole, and there are no semihosting
+     * system calls for sockets and the like, that means this descriptor
+     * must be a normal file.  Normal files never block and are thus
+     * always ready.
+     */
+    complete(cs, cond & (G_IO_IN | G_IO_OUT), 0);
+}
+#endif
+
 /*
  * Static file semihosting syscall implementations.
  */
@@ -628,6 +643,34 @@  static void console_fstat(CPUState *cs, gdb_syscall_complete_cb complete,
     complete(cs, ret ? -1 : 0, ret ? -ret : 0);
 }
 
+#ifndef CONFIG_USER_ONLY
+static void console_poll_one(CPUState *cs, gdb_syscall_complete_cb complete,
+                             GuestFD *gf, GIOCondition cond, int timeout)
+{
+    /* The semihosting console does not support urgent data or errors. */
+    cond &= G_IO_IN | G_IO_OUT;
+
+    /*
+     * Since qemu_semihosting_console_write never blocks, we can
+     * consider output always ready -- leave G_IO_OUT alone.
+     * All that remains is to conditionally signal input ready.
+     * Since output ready causes an immediate return, only block
+     * for G_IO_IN alone.
+     *
+     * TODO: Implement proper timeout.  For now, only support
+     * indefinite wait or immediate poll.
+     */
+    if (cond == G_IO_IN && timeout < 0) {
+        qemu_semihosting_console_block_until_ready(cs);
+        /* We returned -- input must be ready. */
+    } else if ((cond & G_IO_IN) && !qemu_semihosting_console_ready()) {
+        cond &= ~G_IO_IN;
+    }
+
+    complete(cs, cond, 0);
+}
+#endif
+
 /*
  * Syscall entry points.
  */
@@ -906,3 +949,30 @@  void semihost_sys_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete,
         host_gettimeofday(cs, complete, tv_addr, tz_addr);
     }
 }
+
+#ifndef CONFIG_USER_ONLY
+void semihost_sys_poll_one(CPUState *cs, gdb_syscall_complete_cb complete,
+                           int fd, GIOCondition cond, int timeout)
+{
+    GuestFD *gf = get_guestfd(fd);
+
+    if (!gf) {
+        complete(cs, G_IO_NVAL, 1);
+        return;
+    }
+    switch (gf->type) {
+    case GuestFDGDB:
+        complete(cs, G_IO_NVAL, 1);
+        break;
+    case GuestFDHost:
+        host_poll_one(cs, complete, gf, cond, timeout);
+        break;
+    case GuestFDConsole:
+        console_poll_one(cs, complete, gf, cond, timeout);
+        break;
+    case GuestFDStatic:
+    default:
+        g_assert_not_reached();
+    }
+}
+#endif