All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/74] semihosting cleanup
@ 2022-05-03 19:47 Richard Henderson
  2022-05-03 19:47 ` [PATCH v2 01/74] semihosting: Move exec/softmmu-semi.h to semihosting/softmmu-uaccess.h Richard Henderson
                   ` (73 more replies)
  0 siblings, 74 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: alex.bennee, f4bug, crwulff, laurent, shorne

Changes for v2:
  * Drop m68k and nios2 patches to move semihosting exception to helper.

  * Merge semihosting console into GuestFD.

  * Split syscalls into new files.
    Having them in guestfd.[ch] seemed wrong.

  * Standardize on GDB remote-protocol errno.  Having done this, I'm
    not sure it's the best idea -- mips and xtensa semihosting have a
    larger set of errno values than GDB.  Better, perhaps, to standardize
    on host errno and then convert GDB errno back to host on the way
    out of gdbstub.c:handle_file_io.

  * Convert mips and xtensa to semihosting/syscalls.h

  * Implement rx semihosting, with tests.

Still on the to-do list:

  * Non-Coldfire m68k semihosting.  The libgloss spec says that "bkpt"
    may be used when "halt" is not available in the ISA.  Add m68k
    semihosting tests -- we already have a cross toolchain in docker,
    so this should be easy.

  * Support dynamic endianness in arm-compat-semi.c; add tests for
    aarch64 big-endian system mode.

  * Split this patch set.  :-)


r~


Cc: alex.bennee@linaro.org
Cc: f4bug@amsat.org
Cc: crwulff@gmail.com
Cc: laurent@vivier.eu
Cc: shorne@gmail.com


Richard Henderson (74):
  semihosting: Move exec/softmmu-semi.h to semihosting/softmmu-uaccess.h
  semihosting: Return failure from softmmu-uaccess.h functions
  semihosting: Improve condition for config.c and console.c
  semihosting: Move softmmu-uaccess.h functions out of line
  semihosting: Add target_strlen for softmmu-uaccess.h
  semihosting: Simplify softmmu_lock_user_string
  semihosting: Split out guestfd.c
  semihosting: Generalize GuestFDFeatureFile
  semihosting: Return void from do_common_semihosting
  semihosting: Adjust error checking in common_semi_cb
  semihosting: Move common-semi.h to include/semihosting/
  include/exec: Move gdb open flags to gdbstub.h
  include/exec: Move gdb_stat and gdb_timeval to gdbstub.h
  include/exec: Define errno values in gdbstub.h
  semihosting: Use struct gdb_stat in common_semi_flen_cb
  semihosting: Split is_64bit_semihosting per target
  semihosting: Split common_semi_flen_buf per target
  semihosting: Split out common_semi_has_synccache
  semihosting: Use env more often in do_common_semihosting
  semihosting: Move GET_ARG/SET_ARG earlier in the file
  semihosting: Split out semihost_sys_open
  semihosting: Split out semihost_sys_close
  semihosting: Split out semihost_sys_read
  semihosting: Split out semihost_sys_write
  semihosting: Bound length for semihost_sys_{read,write}
  semihosting: Split out semihost_sys_lseek
  semihosting: Split out semihost_sys_isatty
  semihosting: Split out semihost_sys_flen
  semihosting: Split out semihost_sys_remove
  semihosting: Split out semihost_sys_rename
  semihosting: Split out semihost_sys_system
  semihosting: Create semihost_sys_{stat,fstat}
  semihosting: Create semihost_sys_gettimeofday
  gdbstub: Widen gdb_syscall_complete_cb return value
  semihosting: Fix docs comment for qemu_semihosting_console_inc
  semihosting: Pass CPUState to qemu_semihosting_console_inc
  semihosting: Expand qemu_semihosting_console_inc to read
  semihosting: Cleanup chardev init
  semihosting: Create qemu_semihosting_console_write
  semihosting: Add GuestFDConsole
  semihosting: Create qemu_semihosting_guestfd_init
  semihosting: Use console_in_gf for SYS_READC
  semihosting: Use console_out_gf for SYS_WRITEC
  semihosting: Remove qemu_semihosting_console_outc
  semihosting: Use console_out_gf for SYS_WRITE0
  semihosting: Remove qemu_semihosting_console_outs
  semihosting: Create semihost_sys_poll_one
  target/m68k: Eliminate m68k_semi_is_fseek
  target/m68k: Make semihosting system only
  target/m68k: Use semihosting/syscalls.h
  target/nios2: Eliminate nios2_semi_is_lseek
  target/nios2: Move nios2-semi.c to nios2_softmmu_ss
  target/nios2: Use semihosting/syscalls.h
  target/mips: Use an exception for semihosting
  target/mips: Add UHI errno values
  target/mips: Create report_fault for semihosting
  target/mips: Drop link syscall from semihosting
  target/mips: Drop pread and pwrite syscalls from semihosting
  target/mips: Use semihosting/syscalls.h
  target/mips: Avoid qemu_semihosting_log_out for UHI_plog
  target/mips: Use error_report for UHI_assert
  semihosting: Remove qemu_semihosting_log_out
  target/mips: Simplify UHI_argnlen and UHI_argn
  target/mips: Remove GET_TARGET_STRING and FREE_TARGET_STRING
  target/xtensa: Use an exception for semihosting
  target/xtensa: Use semihosting/syscalls.h
  tests/docker: Add debian-rx-cross image
  hw/rx: Handle a kernel file that is ELF
  target/rx: Fix the base of the fixed vector table
  target/rx: Name the exceptions
  target/rx: Consolidate exception helpers
  target/rx: Cleanup rx_cpu_do_interrupt
  target/rx: Implement libgloss semihosting
  tests/tcg/rx: Enable semihosting multiarch tests

 configs/devices/rx-softmmu/default.mak        |    1 +
 configs/targets/aarch64-linux-user.mak        |    1 +
 configs/targets/aarch64_be-linux-user.mak     |    1 +
 configs/targets/arm-linux-user.mak            |    1 +
 configs/targets/armeb-linux-user.mak          |    1 +
 configs/targets/riscv32-linux-user.mak        |    1 +
 configs/targets/riscv64-linux-user.mak        |    1 +
 include/exec/gdbstub.h                        |   67 +-
 include/exec/softmmu-semi.h                   |  101 --
 .../semihosting}/common-semi.h                |    2 +-
 include/semihosting/console.h                 |   74 +-
 include/semihosting/guestfd.h                 |   52 +
 include/semihosting/semihost.h                |   14 +-
 include/semihosting/softmmu-uaccess.h         |   59 +
 include/semihosting/syscalls.h                |   75 ++
 target/arm/common-semi-target.h               |   62 +
 target/mips/cpu.h                             |    3 +-
 target/mips/tcg/tcg-internal.h                |    2 +
 target/riscv/common-semi-target.h             |   50 +
 target/rx/cpu.h                               |   26 +
 target/rx/helper.h                            |    6 +-
 target/xtensa/cpu.h                           |    3 +-
 target/xtensa/helper.h                        |    3 -
 target/mips/tcg/sysemu_helper.h.inc           |    2 -
 gdbstub.c                                     |    7 +-
 hw/rx/rx-gdbsim.c                             |   24 +-
 hw/xtensa/sim.c                               |    3 -
 linux-user/aarch64/cpu_loop.c                 |    2 +-
 linux-user/arm/cpu_loop.c                     |    2 +-
 linux-user/m68k/cpu_loop.c                    |    5 -
 linux-user/main.c                             |    9 +
 linux-user/riscv/cpu_loop.c                   |    2 +-
 linux-user/semihost.c                         |   48 +-
 semihosting/arm-compat-semi.c                 |  987 ++++------------
 semihosting/config.c                          |   17 +-
 semihosting/console.c                         |  144 +--
 semihosting/guestfd.c                         |  160 +++
 semihosting/syscalls.c                        | 1008 +++++++++++++++++
 semihosting/uaccess.c                         |   71 ++
 softmmu/vl.c                                  |    3 +-
 stubs/semihost.c                              |    6 +-
 target/arm/helper.c                           |    4 +-
 target/arm/m_helper.c                         |    2 +-
 target/m68k/m68k-semi.c                       |  368 +-----
 target/mips/tcg/exception.c                   |    1 +
 target/mips/tcg/sysemu/mips-semi.c            |  468 ++++----
 target/mips/tcg/sysemu/tlb_helper.c           |    4 +
 target/mips/tcg/translate.c                   |   12 +-
 target/nios2/nios2-semi.c                     |  354 +-----
 target/riscv/cpu_helper.c                     |    2 +-
 target/rx/helper.c                            |  116 +-
 target/rx/op_helper.c                         |   30 +-
 target/rx/rx-semi.c                           |  165 +++
 target/rx/translate.c                         |   28 +-
 target/xtensa/exc_helper.c                    |    4 +
 target/xtensa/translate.c                     |    3 +-
 target/xtensa/xtensa-semi.c                   |  306 ++---
 tests/tcg/rx/outc.c                           |   15 +
 target/mips/tcg/micromips_translate.c.inc     |    6 +-
 target/mips/tcg/mips16e_translate.c.inc       |    2 +-
 target/mips/tcg/nanomips_translate.c.inc      |    4 +-
 MAINTAINERS                                   |    1 +
 qemu-options.hx                               |   13 +-
 semihosting/meson.build                       |    6 +
 target/m68k/meson.build                       |    6 +-
 target/nios2/meson.build                      |    4 +-
 target/rx/meson.build                         |    4 +-
 tests/docker/Makefile.include                 |    6 +
 .../debian-rx-cross.d/build-toolchain.sh      |   58 +
 tests/tcg/configure.sh                        |    6 +
 tests/tcg/rx/Makefile.softmmu-target          |   24 +
 71 files changed, 2825 insertions(+), 2303 deletions(-)
 delete mode 100644 include/exec/softmmu-semi.h
 rename {semihosting => include/semihosting}/common-semi.h (96%)
 create mode 100644 include/semihosting/guestfd.h
 create mode 100644 include/semihosting/softmmu-uaccess.h
 create mode 100644 include/semihosting/syscalls.h
 create mode 100644 target/arm/common-semi-target.h
 create mode 100644 target/riscv/common-semi-target.h
 create mode 100644 semihosting/guestfd.c
 create mode 100644 semihosting/syscalls.c
 create mode 100644 semihosting/uaccess.c
 create mode 100644 target/rx/rx-semi.c
 create mode 100644 tests/tcg/rx/outc.c
 create mode 100755 tests/docker/dockerfiles/debian-rx-cross.d/build-toolchain.sh
 create mode 100644 tests/tcg/rx/Makefile.softmmu-target

-- 
2.34.1



^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v2 01/74] semihosting: Move exec/softmmu-semi.h to semihosting/softmmu-uaccess.h
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
@ 2022-05-03 19:47 ` Richard Henderson
  2022-05-16 14:36   ` Peter Maydell
  2022-05-03 19:47 ` [PATCH v2 02/74] semihosting: Return failure from softmmu-uaccess.h functions Richard Henderson
                   ` (72 subsequent siblings)
  73 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:47 UTC (permalink / raw)
  To: qemu-devel

We have a subdirectory for semihosting; move this file out of exec.
Rename to emphasize the contents are a replacement for the functions
in linux-user/bsd-user uaccess.c.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 .../{exec/softmmu-semi.h => semihosting/softmmu-uaccess.h}  | 6 +++---
 semihosting/arm-compat-semi.c                               | 2 +-
 target/m68k/m68k-semi.c                                     | 2 +-
 target/mips/tcg/sysemu/mips-semi.c                          | 2 +-
 target/nios2/nios2-semi.c                                   | 2 +-
 5 files changed, 7 insertions(+), 7 deletions(-)
 rename include/{exec/softmmu-semi.h => semihosting/softmmu-uaccess.h} (95%)

diff --git a/include/exec/softmmu-semi.h b/include/semihosting/softmmu-uaccess.h
similarity index 95%
rename from include/exec/softmmu-semi.h
rename to include/semihosting/softmmu-uaccess.h
index fbcae88f4b..e69e3c8548 100644
--- a/include/exec/softmmu-semi.h
+++ b/include/semihosting/softmmu-uaccess.h
@@ -7,8 +7,8 @@
  * This code is licensed under the GPL
  */
 
-#ifndef SOFTMMU_SEMI_H
-#define SOFTMMU_SEMI_H
+#ifndef SEMIHOSTING_SOFTMMU_UACCESS_H
+#define SEMIHOSTING_SOFTMMU_UACCESS_H
 
 #include "cpu.h"
 
@@ -98,4 +98,4 @@ static void softmmu_unlock_user(CPUArchState *env, void *p, target_ulong addr,
 }
 #define unlock_user(s, args, len) softmmu_unlock_user(env, s, args, len)
 
-#endif
+#endif /* SEMIHOSTING_SOFTMMU_UACCESS_H */
diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index 7a51fd0737..dbef280b87 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -370,7 +370,7 @@ static GuestFD *get_guestfd(int guestfd)
 #ifndef CONFIG_USER_ONLY
 static target_ulong syscall_err;
 
-#include "exec/softmmu-semi.h"
+#include "semihosting/softmmu-uaccess.h"
 #endif
 
 static inline uint32_t set_swi_errno(CPUState *cs, uint32_t code)
diff --git a/target/m68k/m68k-semi.c b/target/m68k/m68k-semi.c
index 37343d47e2..a31db38fc3 100644
--- a/target/m68k/m68k-semi.c
+++ b/target/m68k/m68k-semi.c
@@ -25,7 +25,7 @@
 #include "qemu.h"
 #define SEMIHOSTING_HEAP_SIZE (128 * 1024 * 1024)
 #else
-#include "exec/softmmu-semi.h"
+#include "semihosting/softmmu-uaccess.h"
 #include "hw/boards.h"
 #endif
 #include "qemu/log.h"
diff --git a/target/mips/tcg/sysemu/mips-semi.c b/target/mips/tcg/sysemu/mips-semi.c
index b4a383ae90..6d6296e709 100644
--- a/target/mips/tcg/sysemu/mips-semi.c
+++ b/target/mips/tcg/sysemu/mips-semi.c
@@ -21,7 +21,7 @@
 #include "cpu.h"
 #include "qemu/log.h"
 #include "exec/helper-proto.h"
-#include "exec/softmmu-semi.h"
+#include "semihosting/softmmu-uaccess.h"
 #include "semihosting/semihost.h"
 #include "semihosting/console.h"
 
diff --git a/target/nios2/nios2-semi.c b/target/nios2/nios2-semi.c
index ec88474a73..373e6b9436 100644
--- a/target/nios2/nios2-semi.c
+++ b/target/nios2/nios2-semi.c
@@ -28,7 +28,7 @@
 #if defined(CONFIG_USER_ONLY)
 #include "qemu.h"
 #else
-#include "exec/softmmu-semi.h"
+#include "semihosting/softmmu-uaccess.h"
 #endif
 #include "qemu/log.h"
 
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 02/74] semihosting: Return failure from softmmu-uaccess.h functions
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
  2022-05-03 19:47 ` [PATCH v2 01/74] semihosting: Move exec/softmmu-semi.h to semihosting/softmmu-uaccess.h Richard Henderson
@ 2022-05-03 19:47 ` Richard Henderson
  2022-05-16 14:42   ` Peter Maydell
  2022-05-03 19:47 ` [PATCH v2 03/74] semihosting: Improve condition for config.c and console.c Richard Henderson
                   ` (71 subsequent siblings)
  73 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:47 UTC (permalink / raw)
  To: qemu-devel

We were reporting unconditional success for these functions;
pass on any failure from cpu_memory_rw_debug.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/semihosting/softmmu-uaccess.h | 91 ++++++++++++---------------
 1 file changed, 39 insertions(+), 52 deletions(-)

diff --git a/include/semihosting/softmmu-uaccess.h b/include/semihosting/softmmu-uaccess.h
index e69e3c8548..5246a91570 100644
--- a/include/semihosting/softmmu-uaccess.h
+++ b/include/semihosting/softmmu-uaccess.h
@@ -12,82 +12,69 @@
 
 #include "cpu.h"
 
-static inline uint64_t softmmu_tget64(CPUArchState *env, target_ulong addr)
-{
-    uint64_t val;
+#define get_user_u64(val, addr)                                         \
+    ({ uint64_t val_ = 0;                                               \
+       int ret_ = cpu_memory_rw_debug(env_cpu(env), (addr),             \
+                                      &val_, sizeof(val_), 0);          \
+       (val) = tswap64(val_); ret_; })
 
-    cpu_memory_rw_debug(env_cpu(env), addr, (uint8_t *)&val, 8, 0);
-    return tswap64(val);
-}
+#define get_user_u32(val, addr)                                         \
+    ({ uint32_t val_ = 0;                                               \
+       int ret_ = cpu_memory_rw_debug(env_cpu(env), (addr),             \
+                                      &val_, sizeof(val_), 0);          \
+       (val) = tswap32(val_); ret_; })
 
-static inline uint32_t softmmu_tget32(CPUArchState *env, target_ulong addr)
-{
-    uint32_t val;
+#define get_user_u8(val, addr)                                          \
+    ({ uint8_t val_ = 0;                                                \
+       int ret_ = cpu_memory_rw_debug(env_cpu(env), (addr),             \
+                                      &val_, sizeof(val_), 0);          \
+       (val) = val_; ret_; })
 
-    cpu_memory_rw_debug(env_cpu(env), addr, (uint8_t *)&val, 4, 0);
-    return tswap32(val);
-}
-
-static inline uint32_t softmmu_tget8(CPUArchState *env, target_ulong addr)
-{
-    uint8_t val;
-
-    cpu_memory_rw_debug(env_cpu(env), addr, &val, 1, 0);
-    return val;
-}
-
-#define get_user_u64(arg, p) ({ arg = softmmu_tget64(env, p); 0; })
-#define get_user_u32(arg, p) ({ arg = softmmu_tget32(env, p) ; 0; })
-#define get_user_u8(arg, p) ({ arg = softmmu_tget8(env, p) ; 0; })
 #define get_user_ual(arg, p) get_user_u32(arg, p)
 
-static inline void softmmu_tput64(CPUArchState *env,
-                                  target_ulong addr, uint64_t val)
-{
-    val = tswap64(val);
-    cpu_memory_rw_debug(env_cpu(env), addr, (uint8_t *)&val, 8, 1);
-}
+#define put_user_u64(val, addr)                                         \
+    ({ uint64_t val_ = tswap64(val);                                    \
+       cpu_memory_rw_debug(env_cpu(env), (addr), &val_, sizeof(val_), 1); })
+
+#define put_user_u32(val, addr)                                         \
+    ({ uint32_t val_ = tswap32(val);                                    \
+       cpu_memory_rw_debug(env_cpu(env), (addr), &val_, sizeof(val_), 1); })
 
-static inline void softmmu_tput32(CPUArchState *env,
-                                  target_ulong addr, uint32_t val)
-{
-    val = tswap32(val);
-    cpu_memory_rw_debug(env_cpu(env), addr, (uint8_t *)&val, 4, 1);
-}
-#define put_user_u64(arg, p) ({ softmmu_tput64(env, p, arg) ; 0; })
-#define put_user_u32(arg, p) ({ softmmu_tput32(env, p, arg) ; 0; })
 #define put_user_ual(arg, p) put_user_u32(arg, p)
 
-static void *softmmu_lock_user(CPUArchState *env,
-                               target_ulong addr, target_ulong len, int copy)
+static void *softmmu_lock_user(CPUArchState *env, target_ulong addr,
+                               target_ulong len, bool copy)
 {
-    uint8_t *p;
-    /* TODO: Make this something that isn't fixed size.  */
-    p = malloc(len);
+    void *p = malloc(len);
     if (p && copy) {
-        cpu_memory_rw_debug(env_cpu(env), addr, p, len, 0);
+        if (cpu_memory_rw_debug(env_cpu(env), addr, p, len, 0)) {
+            free(p);
+            p = NULL;
+        }
     }
     return p;
 }
 #define lock_user(type, p, len, copy) softmmu_lock_user(env, p, len, copy)
+
 static char *softmmu_lock_user_string(CPUArchState *env, target_ulong addr)
 {
-    char *p;
-    char *s;
-    uint8_t c;
     /* TODO: Make this something that isn't fixed size.  */
-    s = p = malloc(1024);
+    char *s = malloc(1024);
+    size_t len = 0;
+
     if (!s) {
         return NULL;
     }
     do {
-        cpu_memory_rw_debug(env_cpu(env), addr, &c, 1, 0);
-        addr++;
-        *(p++) = c;
-    } while (c);
+        if (cpu_memory_rw_debug(env_cpu(env), addr++, s + len, 1, 0)) {
+            free(s);
+            return NULL;
+        }
+    } while (s[len++]);
     return s;
 }
 #define lock_user_string(p) softmmu_lock_user_string(env, p)
+
 static void softmmu_unlock_user(CPUArchState *env, void *p, target_ulong addr,
                                 target_ulong len)
 {
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 03/74] semihosting: Improve condition for config.c and console.c
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
  2022-05-03 19:47 ` [PATCH v2 01/74] semihosting: Move exec/softmmu-semi.h to semihosting/softmmu-uaccess.h Richard Henderson
  2022-05-03 19:47 ` [PATCH v2 02/74] semihosting: Return failure from softmmu-uaccess.h functions Richard Henderson
@ 2022-05-03 19:47 ` Richard Henderson
  2022-05-16 15:00   ` Peter Maydell
  2022-05-03 19:47 ` [PATCH v2 04/74] semihosting: Move softmmu-uaccess.h functions out of line Richard Henderson
                   ` (70 subsequent siblings)
  73 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:47 UTC (permalink / raw)
  To: qemu-devel

While CONFIG_SEMIHOSTING is currently only set for softmmu,
this will not continue to be true.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 semihosting/meson.build | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/semihosting/meson.build b/semihosting/meson.build
index ea8090abe3..4344e43fb9 100644
--- a/semihosting/meson.build
+++ b/semihosting/meson.build
@@ -1,4 +1,4 @@
-specific_ss.add(when: 'CONFIG_SEMIHOSTING', if_true: files(
+specific_ss.add(when: ['CONFIG_SEMIHOSTING', 'CONFIG_SOFTMMU'], if_true: files(
   'config.c',
   'console.c',
 ))
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 04/74] semihosting: Move softmmu-uaccess.h functions out of line
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (2 preceding siblings ...)
  2022-05-03 19:47 ` [PATCH v2 03/74] semihosting: Improve condition for config.c and console.c Richard Henderson
@ 2022-05-03 19:47 ` Richard Henderson
  2022-05-16 15:04   ` Peter Maydell
  2022-05-03 19:47 ` [PATCH v2 05/74] semihosting: Add target_strlen for softmmu-uaccess.h Richard Henderson
                   ` (69 subsequent siblings)
  73 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:47 UTC (permalink / raw)
  To: qemu-devel

Rather that static (and not even inline) functions within a
header, move the functions to semihosting/uaccess.c.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/semihosting/softmmu-uaccess.h | 42 +++-------------------
 semihosting/uaccess.c                 | 51 +++++++++++++++++++++++++++
 semihosting/meson.build               |  1 +
 3 files changed, 57 insertions(+), 37 deletions(-)
 create mode 100644 semihosting/uaccess.c

diff --git a/include/semihosting/softmmu-uaccess.h b/include/semihosting/softmmu-uaccess.h
index 5246a91570..03300376d3 100644
--- a/include/semihosting/softmmu-uaccess.h
+++ b/include/semihosting/softmmu-uaccess.h
@@ -42,47 +42,15 @@
 
 #define put_user_ual(arg, p) put_user_u32(arg, p)
 
-static void *softmmu_lock_user(CPUArchState *env, target_ulong addr,
-                               target_ulong len, bool copy)
-{
-    void *p = malloc(len);
-    if (p && copy) {
-        if (cpu_memory_rw_debug(env_cpu(env), addr, p, len, 0)) {
-            free(p);
-            p = NULL;
-        }
-    }
-    return p;
-}
+void *softmmu_lock_user(CPUArchState *env, target_ulong addr,
+                        target_ulong len, bool copy);
 #define lock_user(type, p, len, copy) softmmu_lock_user(env, p, len, copy)
 
-static char *softmmu_lock_user_string(CPUArchState *env, target_ulong addr)
-{
-    /* TODO: Make this something that isn't fixed size.  */
-    char *s = malloc(1024);
-    size_t len = 0;
-
-    if (!s) {
-        return NULL;
-    }
-    do {
-        if (cpu_memory_rw_debug(env_cpu(env), addr++, s + len, 1, 0)) {
-            free(s);
-            return NULL;
-        }
-    } while (s[len++]);
-    return s;
-}
+char *softmmu_lock_user_string(CPUArchState *env, target_ulong addr);
 #define lock_user_string(p) softmmu_lock_user_string(env, p)
 
-static void softmmu_unlock_user(CPUArchState *env, void *p, target_ulong addr,
-                                target_ulong len)
-{
-    if (len) {
-        cpu_memory_rw_debug(env_cpu(env), addr, p, len, 1);
-    }
-    free(p);
-}
+void softmmu_unlock_user(CPUArchState *env, void *p,
+                         target_ulong addr, target_ulong len);
 #define unlock_user(s, args, len) softmmu_unlock_user(env, s, args, len)
 
 #endif /* SEMIHOSTING_SOFTMMU_UACCESS_H */
diff --git a/semihosting/uaccess.c b/semihosting/uaccess.c
new file mode 100644
index 0000000000..0d3b32b75d
--- /dev/null
+++ b/semihosting/uaccess.c
@@ -0,0 +1,51 @@
+/*
+ * Helper routines to provide target memory access for semihosting
+ * syscalls in system emulation mode.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * This code is licensed under the GPL
+ */
+
+#include "qemu/osdep.h"
+#include "semihosting/softmmu-uaccess.h"
+
+void *softmmu_lock_user(CPUArchState *env, target_ulong addr,
+                        target_ulong len, bool copy)
+{
+    void *p = malloc(len);
+    if (p && copy) {
+        if (cpu_memory_rw_debug(env_cpu(env), addr, p, len, 0)) {
+            free(p);
+            p = NULL;
+        }
+    }
+    return p;
+}
+
+char *softmmu_lock_user_string(CPUArchState *env, target_ulong addr)
+{
+    /* TODO: Make this something that isn't fixed size.  */
+    char *s = malloc(1024);
+    size_t len = 0;
+
+    if (!s) {
+        return NULL;
+    }
+    do {
+        if (cpu_memory_rw_debug(env_cpu(env), addr++, s + len, 1, 0)) {
+            free(s);
+            return NULL;
+        }
+    } while (s[len++]);
+    return s;
+}
+
+void softmmu_unlock_user(CPUArchState *env, void *p,
+                         target_ulong addr, target_ulong len)
+{
+    if (len) {
+        cpu_memory_rw_debug(env_cpu(env), addr, p, len, 1);
+    }
+    free(p);
+}
diff --git a/semihosting/meson.build b/semihosting/meson.build
index 4344e43fb9..10b3b99921 100644
--- a/semihosting/meson.build
+++ b/semihosting/meson.build
@@ -1,6 +1,7 @@
 specific_ss.add(when: ['CONFIG_SEMIHOSTING', 'CONFIG_SOFTMMU'], if_true: files(
   'config.c',
   'console.c',
+  'uaccess.c',
 ))
 
 specific_ss.add(when: ['CONFIG_ARM_COMPATIBLE_SEMIHOSTING'],
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 05/74] semihosting: Add target_strlen for softmmu-uaccess.h
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (3 preceding siblings ...)
  2022-05-03 19:47 ` [PATCH v2 04/74] semihosting: Move softmmu-uaccess.h functions out of line Richard Henderson
@ 2022-05-03 19:47 ` Richard Henderson
  2022-05-16 15:11   ` Peter Maydell
  2022-05-03 19:47 ` [PATCH v2 06/74] semihosting: Simplify softmmu_lock_user_string Richard Henderson
                   ` (68 subsequent siblings)
  73 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:47 UTC (permalink / raw)
  To: qemu-devel

Mirror the user-only function of the same name.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/semihosting/softmmu-uaccess.h |  3 +++
 semihosting/uaccess.c                 | 29 +++++++++++++++++++++++++++
 2 files changed, 32 insertions(+)

diff --git a/include/semihosting/softmmu-uaccess.h b/include/semihosting/softmmu-uaccess.h
index 03300376d3..4f08dfc098 100644
--- a/include/semihosting/softmmu-uaccess.h
+++ b/include/semihosting/softmmu-uaccess.h
@@ -53,4 +53,7 @@ void softmmu_unlock_user(CPUArchState *env, void *p,
                          target_ulong addr, target_ulong len);
 #define unlock_user(s, args, len) softmmu_unlock_user(env, s, args, len)
 
+ssize_t softmmu_strlen_user(CPUArchState *env, target_ulong addr);
+#define target_strlen(p) softmmu_strlen_user(env, p)
+
 #endif /* SEMIHOSTING_SOFTMMU_UACCESS_H */
diff --git a/semihosting/uaccess.c b/semihosting/uaccess.c
index 0d3b32b75d..3cd809122c 100644
--- a/semihosting/uaccess.c
+++ b/semihosting/uaccess.c
@@ -23,6 +23,35 @@ void *softmmu_lock_user(CPUArchState *env, target_ulong addr,
     return p;
 }
 
+ssize_t softmmu_strlen_user(CPUArchState *env, target_ulong addr)
+{
+    char buf[256];
+    size_t len = 0;
+
+    while (1) {
+        size_t chunk;
+        char *p;
+
+        chunk = -(addr | TARGET_PAGE_MASK);
+        chunk = MIN(chunk, sizeof(buf));
+
+        if (cpu_memory_rw_debug(env_cpu(env), addr, buf, chunk, 0)) {
+            return -1;
+        }
+        p = memchr(buf, 0, chunk);
+        if (p) {
+            len += p - buf;
+            return len <= INT32_MAX ? (ssize_t)len : -1;
+        }
+
+        len += chunk;
+        addr += chunk;
+        if (len > INT32_MAX) {
+            return -1;
+        }
+    }
+}
+
 char *softmmu_lock_user_string(CPUArchState *env, target_ulong addr)
 {
     /* TODO: Make this something that isn't fixed size.  */
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 06/74] semihosting: Simplify softmmu_lock_user_string
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (4 preceding siblings ...)
  2022-05-03 19:47 ` [PATCH v2 05/74] semihosting: Add target_strlen for softmmu-uaccess.h Richard Henderson
@ 2022-05-03 19:47 ` Richard Henderson
  2022-05-16 15:12   ` Peter Maydell
  2022-05-03 19:47 ` [PATCH v2 07/74] semihosting: Split out guestfd.c Richard Henderson
                   ` (67 subsequent siblings)
  73 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:47 UTC (permalink / raw)
  To: qemu-devel

We are not currently bounding the search to the 1024 bytes
that we allocated, possibly overrunning the buffer.
Use softmmu_strlen_user to find the length and allocate the
correct size from the beginning.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 semihosting/uaccess.c | 15 +++------------
 1 file changed, 3 insertions(+), 12 deletions(-)

diff --git a/semihosting/uaccess.c b/semihosting/uaccess.c
index 3cd809122c..f5fc94c401 100644
--- a/semihosting/uaccess.c
+++ b/semihosting/uaccess.c
@@ -54,20 +54,11 @@ ssize_t softmmu_strlen_user(CPUArchState *env, target_ulong addr)
 
 char *softmmu_lock_user_string(CPUArchState *env, target_ulong addr)
 {
-    /* TODO: Make this something that isn't fixed size.  */
-    char *s = malloc(1024);
-    size_t len = 0;
-
-    if (!s) {
+    ssize_t len = softmmu_strlen_user(env, addr);
+    if (len < 0) {
         return NULL;
     }
-    do {
-        if (cpu_memory_rw_debug(env_cpu(env), addr++, s + len, 1, 0)) {
-            free(s);
-            return NULL;
-        }
-    } while (s[len++]);
-    return s;
+    return softmmu_lock_user(env, addr, len + 1, true);
 }
 
 void softmmu_unlock_user(CPUArchState *env, void *p,
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 07/74] semihosting: Split out guestfd.c
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (5 preceding siblings ...)
  2022-05-03 19:47 ` [PATCH v2 06/74] semihosting: Simplify softmmu_lock_user_string Richard Henderson
@ 2022-05-03 19:47 ` Richard Henderson
  2022-05-16 15:14   ` Peter Maydell
  2022-05-03 19:47 ` [PATCH v2 08/74] semihosting: Generalize GuestFDFeatureFile Richard Henderson
                   ` (66 subsequent siblings)
  73 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:47 UTC (permalink / raw)
  To: qemu-devel

In arm-compat-semi.c, we have more advanced treatment of
guest file descriptors than we do in other implementations.
Split out GuestFD and related functions to a new file so
that they can be shared.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 configs/targets/aarch64-linux-user.mak    |   1 +
 configs/targets/aarch64_be-linux-user.mak |   1 +
 configs/targets/arm-linux-user.mak        |   1 +
 configs/targets/armeb-linux-user.mak      |   1 +
 configs/targets/riscv32-linux-user.mak    |   1 +
 configs/targets/riscv64-linux-user.mak    |   1 +
 include/semihosting/guestfd.h             |  40 +++++++
 semihosting/arm-compat-semi.c             | 125 +---------------------
 semihosting/guestfd.c                     | 116 ++++++++++++++++++++
 semihosting/meson.build                   |   4 +
 10 files changed, 168 insertions(+), 123 deletions(-)
 create mode 100644 include/semihosting/guestfd.h
 create mode 100644 semihosting/guestfd.c

diff --git a/configs/targets/aarch64-linux-user.mak b/configs/targets/aarch64-linux-user.mak
index d0c603c54e..db552f1839 100644
--- a/configs/targets/aarch64-linux-user.mak
+++ b/configs/targets/aarch64-linux-user.mak
@@ -2,4 +2,5 @@ TARGET_ARCH=aarch64
 TARGET_BASE_ARCH=arm
 TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml
 TARGET_HAS_BFLT=y
+CONFIG_SEMIHOSTING=y
 CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
diff --git a/configs/targets/aarch64_be-linux-user.mak b/configs/targets/aarch64_be-linux-user.mak
index 7794424745..dc78044fb1 100644
--- a/configs/targets/aarch64_be-linux-user.mak
+++ b/configs/targets/aarch64_be-linux-user.mak
@@ -3,4 +3,5 @@ TARGET_BASE_ARCH=arm
 TARGET_BIG_ENDIAN=y
 TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml
 TARGET_HAS_BFLT=y
+CONFIG_SEMIHOSTING=y
 CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
diff --git a/configs/targets/arm-linux-user.mak b/configs/targets/arm-linux-user.mak
index 3e10d6b15d..7f5d65794c 100644
--- a/configs/targets/arm-linux-user.mak
+++ b/configs/targets/arm-linux-user.mak
@@ -3,4 +3,5 @@ TARGET_SYSTBL_ABI=common,oabi
 TARGET_SYSTBL=syscall.tbl
 TARGET_XML_FILES= gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-vfp-sysregs.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml gdb-xml/arm-m-profile-mve.xml
 TARGET_HAS_BFLT=y
+CONFIG_SEMIHOSTING=y
 CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
diff --git a/configs/targets/armeb-linux-user.mak b/configs/targets/armeb-linux-user.mak
index a249cc2e29..943d0d87bf 100644
--- a/configs/targets/armeb-linux-user.mak
+++ b/configs/targets/armeb-linux-user.mak
@@ -4,4 +4,5 @@ TARGET_SYSTBL=syscall.tbl
 TARGET_BIG_ENDIAN=y
 TARGET_XML_FILES= gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-vfp-sysregs.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml gdb-xml/arm-m-profile-mve.xml
 TARGET_HAS_BFLT=y
+CONFIG_SEMIHOSTING=y
 CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
diff --git a/configs/targets/riscv32-linux-user.mak b/configs/targets/riscv32-linux-user.mak
index bd2f1fd497..9761618e67 100644
--- a/configs/targets/riscv32-linux-user.mak
+++ b/configs/targets/riscv32-linux-user.mak
@@ -2,4 +2,5 @@ TARGET_ARCH=riscv32
 TARGET_BASE_ARCH=riscv
 TARGET_ABI_DIR=riscv
 TARGET_XML_FILES= gdb-xml/riscv-32bit-cpu.xml gdb-xml/riscv-32bit-fpu.xml gdb-xml/riscv-64bit-fpu.xml gdb-xml/riscv-32bit-virtual.xml
+CONFIG_SEMIHOSTING=y
 CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
diff --git a/configs/targets/riscv64-linux-user.mak b/configs/targets/riscv64-linux-user.mak
index 4aca7662ce..cfd1fd382f 100644
--- a/configs/targets/riscv64-linux-user.mak
+++ b/configs/targets/riscv64-linux-user.mak
@@ -2,4 +2,5 @@ TARGET_ARCH=riscv64
 TARGET_BASE_ARCH=riscv
 TARGET_ABI_DIR=riscv
 TARGET_XML_FILES= gdb-xml/riscv-64bit-cpu.xml gdb-xml/riscv-32bit-fpu.xml gdb-xml/riscv-64bit-fpu.xml gdb-xml/riscv-64bit-virtual.xml
+CONFIG_SEMIHOSTING=y
 CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
diff --git a/include/semihosting/guestfd.h b/include/semihosting/guestfd.h
new file mode 100644
index 0000000000..5d6e744305
--- /dev/null
+++ b/include/semihosting/guestfd.h
@@ -0,0 +1,40 @@
+/*
+ * Hosted file support for semihosting syscalls.
+ *
+ * Copyright (c) 2005, 2007 CodeSourcery.
+ * Copyright (c) 2019 Linaro
+ * Copyright © 2020 by Keith Packard <keithp@keithp.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef SEMIHOSTING_GUESTFD_H
+#define SEMIHOSTING_GUESTFD_H
+
+typedef enum GuestFDType {
+    GuestFDUnused = 0,
+    GuestFDHost = 1,
+    GuestFDGDB = 2,
+    GuestFDFeatureFile = 3,
+} GuestFDType;
+
+/*
+ * Guest file descriptors are integer indexes into an array of
+ * these structures (we will dynamically resize as necessary).
+ */
+typedef struct GuestFD {
+    GuestFDType type;
+    union {
+        int hostfd;
+        unsigned featurefile_offset;
+    };
+} GuestFD;
+
+int alloc_guestfd(void);
+void dealloc_guestfd(int guestfd);
+GuestFD *get_guestfd(int guestfd);
+
+void associate_guestfd(int guestfd, int hostfd);
+void init_featurefile_guestfd(int guestfd);
+
+#endif /* SEMIHOSTING_GUESTFD_H */
diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index dbef280b87..c092138031 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -32,12 +32,13 @@
  */
 
 #include "qemu/osdep.h"
-
 #include "semihosting/semihost.h"
 #include "semihosting/console.h"
 #include "semihosting/common-semi.h"
+#include "semihosting/guestfd.h"
 #include "qemu/timer.h"
 #include "exec/gdbstub.h"
+
 #ifdef CONFIG_USER_ONLY
 #include "qemu.h"
 
@@ -123,27 +124,6 @@ static int open_modeflags[12] = {
     O_RDWR | O_CREAT | O_APPEND | O_BINARY
 };
 
-typedef enum GuestFDType {
-    GuestFDUnused = 0,
-    GuestFDHost = 1,
-    GuestFDGDB = 2,
-    GuestFDFeatureFile = 3,
-} GuestFDType;
-
-/*
- * Guest file descriptors are integer indexes into an array of
- * these structures (we will dynamically resize as necessary).
- */
-typedef struct GuestFD {
-    GuestFDType type;
-    union {
-        int hostfd;
-        target_ulong featurefile_offset;
-    };
-} GuestFD;
-
-static GArray *guestfd_array;
-
 #ifndef CONFIG_USER_ONLY
 
 /**
@@ -268,98 +248,6 @@ common_semi_sys_exit_extended(CPUState *cs, int nr)
 
 #endif
 
-/*
- * Allocate a new guest file descriptor and return it; if we
- * couldn't allocate a new fd then return -1.
- * This is a fairly simplistic implementation because we don't
- * expect that most semihosting guest programs will make very
- * heavy use of opening and closing fds.
- */
-static int alloc_guestfd(void)
-{
-    guint i;
-
-    if (!guestfd_array) {
-        /* New entries zero-initialized, i.e. type GuestFDUnused */
-        guestfd_array = g_array_new(FALSE, TRUE, sizeof(GuestFD));
-    }
-
-    /* SYS_OPEN should return nonzero handle on success. Start guestfd from 1 */
-    for (i = 1; i < guestfd_array->len; i++) {
-        GuestFD *gf = &g_array_index(guestfd_array, GuestFD, i);
-
-        if (gf->type == GuestFDUnused) {
-            return i;
-        }
-    }
-
-    /* All elements already in use: expand the array */
-    g_array_set_size(guestfd_array, i + 1);
-    return i;
-}
-
-/*
- * Look up the guestfd in the data structure; return NULL
- * for out of bounds, but don't check whether the slot is unused.
- * This is used internally by the other guestfd functions.
- */
-static GuestFD *do_get_guestfd(int guestfd)
-{
-    if (!guestfd_array) {
-        return NULL;
-    }
-
-    if (guestfd <= 0 || guestfd >= guestfd_array->len) {
-        return NULL;
-    }
-
-    return &g_array_index(guestfd_array, GuestFD, guestfd);
-}
-
-/*
- * Associate the specified guest fd (which must have been
- * allocated via alloc_fd() and not previously used) with
- * the specified host/gdb fd.
- */
-static void associate_guestfd(int guestfd, int hostfd)
-{
-    GuestFD *gf = do_get_guestfd(guestfd);
-
-    assert(gf);
-    gf->type = use_gdb_syscalls() ? GuestFDGDB : GuestFDHost;
-    gf->hostfd = hostfd;
-}
-
-/*
- * Deallocate the specified guest file descriptor. This doesn't
- * close the host fd, it merely undoes the work of alloc_fd().
- */
-static void dealloc_guestfd(int guestfd)
-{
-    GuestFD *gf = do_get_guestfd(guestfd);
-
-    assert(gf);
-    gf->type = GuestFDUnused;
-}
-
-/*
- * Given a guest file descriptor, get the associated struct.
- * If the fd is not valid, return NULL. This is the function
- * used by the various semihosting calls to validate a handle
- * from the guest.
- * Note: calling alloc_guestfd() or dealloc_guestfd() will
- * invalidate any GuestFD* obtained by calling this function.
- */
-static GuestFD *get_guestfd(int guestfd)
-{
-    GuestFD *gf = do_get_guestfd(guestfd);
-
-    if (!gf || gf->type == GuestFDUnused) {
-        return NULL;
-    }
-    return gf;
-}
-
 /*
  * The semihosting API has no concept of its errno being thread-safe,
  * as the API design predates SMP CPUs and was intended as a simple
@@ -665,15 +553,6 @@ static const uint8_t featurefile_data[] = {
     SH_EXT_EXIT_EXTENDED | SH_EXT_STDOUT_STDERR, /* Feature byte 0 */
 };
 
-static void init_featurefile_guestfd(int guestfd)
-{
-    GuestFD *gf = do_get_guestfd(guestfd);
-
-    assert(gf);
-    gf->type = GuestFDFeatureFile;
-    gf->featurefile_offset = 0;
-}
-
 static uint32_t featurefile_closefn(CPUState *cs, GuestFD *gf)
 {
     /* Nothing to do */
diff --git a/semihosting/guestfd.c b/semihosting/guestfd.c
new file mode 100644
index 0000000000..e77265db0f
--- /dev/null
+++ b/semihosting/guestfd.c
@@ -0,0 +1,116 @@
+/*
+ * Hosted file support for semihosting syscalls.
+ *
+ * Copyright (c) 2005, 2007 CodeSourcery.
+ * Copyright (c) 2019 Linaro
+ * Copyright © 2020 by Keith Packard <keithp@keithp.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "exec/gdbstub.h"
+#include "semihosting/guestfd.h"
+
+static GArray *guestfd_array;
+
+/*
+ * Allocate a new guest file descriptor and return it; if we
+ * couldn't allocate a new fd then return -1.
+ * This is a fairly simplistic implementation because we don't
+ * expect that most semihosting guest programs will make very
+ * heavy use of opening and closing fds.
+ */
+int alloc_guestfd(void)
+{
+    guint i;
+
+    if (!guestfd_array) {
+        /* New entries zero-initialized, i.e. type GuestFDUnused */
+        guestfd_array = g_array_new(FALSE, TRUE, sizeof(GuestFD));
+    }
+
+    /* SYS_OPEN should return nonzero handle on success. Start guestfd from 1 */
+    for (i = 1; i < guestfd_array->len; i++) {
+        GuestFD *gf = &g_array_index(guestfd_array, GuestFD, i);
+
+        if (gf->type == GuestFDUnused) {
+            return i;
+        }
+    }
+
+    /* All elements already in use: expand the array */
+    g_array_set_size(guestfd_array, i + 1);
+    return i;
+}
+
+/*
+ * Look up the guestfd in the data structure; return NULL
+ * for out of bounds, but don't check whether the slot is unused.
+ * This is used internally by the other guestfd functions.
+ */
+static GuestFD *do_get_guestfd(int guestfd)
+{
+    if (!guestfd_array) {
+        return NULL;
+    }
+
+    if (guestfd <= 0 || guestfd >= guestfd_array->len) {
+        return NULL;
+    }
+
+    return &g_array_index(guestfd_array, GuestFD, guestfd);
+}
+
+/*
+ * Given a guest file descriptor, get the associated struct.
+ * If the fd is not valid, return NULL. This is the function
+ * used by the various semihosting calls to validate a handle
+ * from the guest.
+ * Note: calling alloc_guestfd() or dealloc_guestfd() will
+ * invalidate any GuestFD* obtained by calling this function.
+ */
+GuestFD *get_guestfd(int guestfd)
+{
+    GuestFD *gf = do_get_guestfd(guestfd);
+
+    if (!gf || gf->type == GuestFDUnused) {
+        return NULL;
+    }
+    return gf;
+}
+
+/*
+ * Associate the specified guest fd (which must have been
+ * allocated via alloc_fd() and not previously used) with
+ * the specified host/gdb fd.
+ */
+void associate_guestfd(int guestfd, int hostfd)
+{
+    GuestFD *gf = do_get_guestfd(guestfd);
+
+    assert(gf);
+    gf->type = use_gdb_syscalls() ? GuestFDGDB : GuestFDHost;
+    gf->hostfd = hostfd;
+}
+
+void init_featurefile_guestfd(int guestfd)
+{
+    GuestFD *gf = do_get_guestfd(guestfd);
+
+    assert(gf);
+    gf->type = GuestFDFeatureFile;
+    gf->featurefile_offset = 0;
+}
+
+/*
+ * Deallocate the specified guest file descriptor. This doesn't
+ * close the host fd, it merely undoes the work of alloc_fd().
+ */
+void dealloc_guestfd(int guestfd)
+{
+    GuestFD *gf = do_get_guestfd(guestfd);
+
+    assert(gf);
+    gf->type = GuestFDUnused;
+}
diff --git a/semihosting/meson.build b/semihosting/meson.build
index 10b3b99921..d2c1c37bfd 100644
--- a/semihosting/meson.build
+++ b/semihosting/meson.build
@@ -1,3 +1,7 @@
+specific_ss.add(when: 'CONFIG_SEMIHOSTING', if_true: files(
+  'guestfd.c',
+))
+
 specific_ss.add(when: ['CONFIG_SEMIHOSTING', 'CONFIG_SOFTMMU'], if_true: files(
   'config.c',
   'console.c',
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 08/74] semihosting: Generalize GuestFDFeatureFile
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (6 preceding siblings ...)
  2022-05-03 19:47 ` [PATCH v2 07/74] semihosting: Split out guestfd.c Richard Henderson
@ 2022-05-03 19:47 ` Richard Henderson
  2022-05-16 15:20   ` Peter Maydell
  2022-05-03 19:47 ` [PATCH v2 09/74] semihosting: Return void from do_common_semihosting Richard Henderson
                   ` (65 subsequent siblings)
  73 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:47 UTC (permalink / raw)
  To: qemu-devel

Rather than hard-coding the buffer from which we deliver data,
pass it in on initialization.  This decouples the feature from
ARM semihosting.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/semihosting/guestfd.h | 10 ++++++---
 semihosting/arm-compat-semi.c | 39 ++++++++++++++++++-----------------
 semihosting/guestfd.c         |  8 ++++---
 3 files changed, 32 insertions(+), 25 deletions(-)

diff --git a/include/semihosting/guestfd.h b/include/semihosting/guestfd.h
index 5d6e744305..5aa2722cb2 100644
--- a/include/semihosting/guestfd.h
+++ b/include/semihosting/guestfd.h
@@ -15,7 +15,7 @@ typedef enum GuestFDType {
     GuestFDUnused = 0,
     GuestFDHost = 1,
     GuestFDGDB = 2,
-    GuestFDFeatureFile = 3,
+    GuestFDStatic = 3,
 } GuestFDType;
 
 /*
@@ -26,7 +26,11 @@ typedef struct GuestFD {
     GuestFDType type;
     union {
         int hostfd;
-        unsigned featurefile_offset;
+        struct {
+            const uint8_t *data;
+            size_t len;
+            size_t off;
+        } staticfile;
     };
 } GuestFD;
 
@@ -35,6 +39,6 @@ void dealloc_guestfd(int guestfd);
 GuestFD *get_guestfd(int guestfd);
 
 void associate_guestfd(int guestfd, int hostfd);
-void init_featurefile_guestfd(int guestfd);
+void staticfile_guestfd(int guestfd, const uint8_t *data, size_t len);
 
 #endif /* SEMIHOSTING_GUESTFD_H */
diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index c092138031..c6bfd4d1ba 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -553,13 +553,13 @@ static const uint8_t featurefile_data[] = {
     SH_EXT_EXIT_EXTENDED | SH_EXT_STDOUT_STDERR, /* Feature byte 0 */
 };
 
-static uint32_t featurefile_closefn(CPUState *cs, GuestFD *gf)
+static uint32_t staticfile_closefn(CPUState *cs, GuestFD *gf)
 {
     /* Nothing to do */
     return 0;
 }
 
-static uint32_t featurefile_writefn(CPUState *cs, GuestFD *gf,
+static uint32_t staticfile_writefn(CPUState *cs, GuestFD *gf,
                                     target_ulong buf, uint32_t len)
 {
     /* This fd can never be open for writing */
@@ -568,7 +568,7 @@ static uint32_t featurefile_writefn(CPUState *cs, GuestFD *gf,
     return set_swi_errno(cs, -1);
 }
 
-static uint32_t featurefile_readfn(CPUState *cs, GuestFD *gf,
+static uint32_t staticfile_readfn(CPUState *cs, GuestFD *gf,
                                    target_ulong buf, uint32_t len)
 {
     CPUArchState *env = cs->env_ptr;
@@ -582,11 +582,11 @@ static uint32_t featurefile_readfn(CPUState *cs, GuestFD *gf,
     }
 
     for (i = 0; i < len; i++) {
-        if (gf->featurefile_offset >= sizeof(featurefile_data)) {
+        if (gf->staticfile.off >= gf->staticfile.len) {
             break;
         }
-        s[i] = featurefile_data[gf->featurefile_offset];
-        gf->featurefile_offset++;
+        s[i] = gf->staticfile.data[gf->staticfile.off];
+        gf->staticfile.off++;
     }
 
     unlock_user(s, buf, len);
@@ -595,21 +595,21 @@ static uint32_t featurefile_readfn(CPUState *cs, GuestFD *gf,
     return len - i;
 }
 
-static uint32_t featurefile_isattyfn(CPUState *cs, GuestFD *gf)
+static uint32_t staticfile_isattyfn(CPUState *cs, GuestFD *gf)
 {
     return 0;
 }
 
-static uint32_t featurefile_seekfn(CPUState *cs, GuestFD *gf,
+static uint32_t staticfile_seekfn(CPUState *cs, GuestFD *gf,
                                    target_ulong offset)
 {
-    gf->featurefile_offset = offset;
+    gf->staticfile.off = offset;
     return 0;
 }
 
-static uint32_t featurefile_flenfn(CPUState *cs, GuestFD *gf)
+static uint32_t staticfile_flenfn(CPUState *cs, GuestFD *gf)
 {
-    return sizeof(featurefile_data);
+    return gf->staticfile.len;
 }
 
 typedef struct GuestFDFunctions {
@@ -638,13 +638,13 @@ static const GuestFDFunctions guestfd_fns[] = {
         .seekfn = gdb_seekfn,
         .flenfn = gdb_flenfn,
     },
-    [GuestFDFeatureFile] = {
-        .closefn = featurefile_closefn,
-        .writefn = featurefile_writefn,
-        .readfn = featurefile_readfn,
-        .isattyfn = featurefile_isattyfn,
-        .seekfn = featurefile_seekfn,
-        .flenfn = featurefile_flenfn,
+    [GuestFDStatic] = {
+        .closefn = staticfile_closefn,
+        .writefn = staticfile_writefn,
+        .readfn = staticfile_readfn,
+        .isattyfn = staticfile_isattyfn,
+        .seekfn = staticfile_seekfn,
+        .flenfn = staticfile_flenfn,
     },
 };
 
@@ -765,7 +765,8 @@ target_ulong do_common_semihosting(CPUState *cs)
                 errno = EACCES;
                 return set_swi_errno(cs, -1);
             }
-            init_featurefile_guestfd(guestfd);
+            staticfile_guestfd(guestfd, featurefile_data,
+                               sizeof(featurefile_data));
             return guestfd;
         }
 
diff --git a/semihosting/guestfd.c b/semihosting/guestfd.c
index e77265db0f..b6405f5663 100644
--- a/semihosting/guestfd.c
+++ b/semihosting/guestfd.c
@@ -94,13 +94,15 @@ void associate_guestfd(int guestfd, int hostfd)
     gf->hostfd = hostfd;
 }
 
-void init_featurefile_guestfd(int guestfd)
+void staticfile_guestfd(int guestfd, const uint8_t *data, size_t len)
 {
     GuestFD *gf = do_get_guestfd(guestfd);
 
     assert(gf);
-    gf->type = GuestFDFeatureFile;
-    gf->featurefile_offset = 0;
+    gf->type = GuestFDStatic;
+    gf->staticfile.data = data;
+    gf->staticfile.len = len;
+    gf->staticfile.off = 0;
 }
 
 /*
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 09/74] semihosting: Return void from do_common_semihosting
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (7 preceding siblings ...)
  2022-05-03 19:47 ` [PATCH v2 08/74] semihosting: Generalize GuestFDFeatureFile Richard Henderson
@ 2022-05-03 19:47 ` Richard Henderson
  2022-05-16 15:31   ` Peter Maydell
  2022-05-03 19:47 ` [PATCH v2 10/74] semihosting: Adjust error checking in common_semi_cb Richard Henderson
                   ` (64 subsequent siblings)
  73 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:47 UTC (permalink / raw)
  To: qemu-devel

Perform the cleanup in the FIXME comment in common_semi_gdb_syscall.
Do not modify guest registers until the syscall is complete,
which in the gdbstub case is asynchronous.

In the synchronous non-gdbstub case, use common_semi_set_ret
to set the result.  Merge set_swi_errno into common_semi_cb.
Rely on the latter for combined return value / errno setting.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 semihosting/common-semi.h     |   2 +-
 linux-user/aarch64/cpu_loop.c |   2 +-
 linux-user/arm/cpu_loop.c     |   2 +-
 linux-user/riscv/cpu_loop.c   |   2 +-
 semihosting/arm-compat-semi.c | 571 ++++++++++++++++------------------
 target/arm/helper.c           |   4 +-
 target/arm/m_helper.c         |   2 +-
 target/riscv/cpu_helper.c     |   2 +-
 8 files changed, 278 insertions(+), 309 deletions(-)

diff --git a/semihosting/common-semi.h b/semihosting/common-semi.h
index 0bfab1c669..0a91db7c41 100644
--- a/semihosting/common-semi.h
+++ b/semihosting/common-semi.h
@@ -34,6 +34,6 @@
 #ifndef COMMON_SEMI_H
 #define COMMON_SEMI_H
 
-target_ulong do_common_semihosting(CPUState *cs);
+void do_common_semihosting(CPUState *cs);
 
 #endif /* COMMON_SEMI_H */
diff --git a/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c
index 3b273f6299..f7ef36cd9f 100644
--- a/linux-user/aarch64/cpu_loop.c
+++ b/linux-user/aarch64/cpu_loop.c
@@ -154,7 +154,7 @@ void cpu_loop(CPUARMState *env)
             force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
             break;
         case EXCP_SEMIHOST:
-            env->xregs[0] = do_common_semihosting(cs);
+            do_common_semihosting(cs);
             env->pc += 4;
             break;
         case EXCP_YIELD:
diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c
index d950409d5b..c0790f3246 100644
--- a/linux-user/arm/cpu_loop.c
+++ b/linux-user/arm/cpu_loop.c
@@ -449,7 +449,7 @@ void cpu_loop(CPUARMState *env)
             }
             break;
         case EXCP_SEMIHOST:
-            env->regs[0] = do_common_semihosting(cs);
+            do_common_semihosting(cs);
             env->regs[15] += env->thumb ? 2 : 4;
             break;
         case EXCP_INTERRUPT:
diff --git a/linux-user/riscv/cpu_loop.c b/linux-user/riscv/cpu_loop.c
index 29084c1421..bffca7db12 100644
--- a/linux-user/riscv/cpu_loop.c
+++ b/linux-user/riscv/cpu_loop.c
@@ -81,7 +81,7 @@ void cpu_loop(CPURISCVState *env)
             force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
             break;
         case RISCV_EXCP_SEMIHOST:
-            env->gpr[xA0] = do_common_semihosting(cs);
+            do_common_semihosting(cs);
             env->pc += 4;
             break;
         default:
diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index c6bfd4d1ba..7030dfd587 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -261,20 +261,6 @@ static target_ulong syscall_err;
 #include "semihosting/softmmu-uaccess.h"
 #endif
 
-static inline uint32_t set_swi_errno(CPUState *cs, uint32_t code)
-{
-    if (code == (uint32_t)-1) {
-#ifdef CONFIG_USER_ONLY
-        TaskState *ts = cs->opaque;
-
-        ts->swi_errno = errno;
-#else
-        syscall_err = errno;
-#endif
-    }
-    return code;
-}
-
 static inline uint32_t get_swi_errno(CPUState *cs)
 {
 #ifdef CONFIG_USER_ONLY
@@ -290,28 +276,29 @@ static target_ulong common_semi_syscall_len;
 
 static void common_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
 {
-    target_ulong reg0 = common_semi_arg(cs, 0);
-
     if (ret == (target_ulong)-1) {
-        errno = err;
-        set_swi_errno(cs, -1);
-        reg0 = ret;
+#ifdef CONFIG_USER_ONLY
+        TaskState *ts = cs->opaque;
+        ts->swi_errno = err;
+#else
+        syscall_err = err;
+#endif
     } else {
         /* Fixup syscalls that use nonstardard return conventions.  */
+        target_ulong reg0 = common_semi_arg(cs, 0);
         switch (reg0) {
         case TARGET_SYS_WRITE:
         case TARGET_SYS_READ:
-            reg0 = common_semi_syscall_len - ret;
+            ret = common_semi_syscall_len - ret;
             break;
         case TARGET_SYS_SEEK:
-            reg0 = 0;
+            ret = 0;
             break;
         default:
-            reg0 = ret;
             break;
         }
     }
-    common_semi_set_ret(cs, reg0);
+    common_semi_set_ret(cs, ret);
 }
 
 static target_ulong common_semi_flen_buf(CPUState *cs)
@@ -351,9 +338,8 @@ common_semi_flen_cb(CPUState *cs, target_ulong ret, target_ulong err)
     cpu_memory_rw_debug(cs, common_semi_flen_buf(cs) + 32,
                         (uint8_t *)&size, 4, 0);
     size = be32_to_cpu(size);
+    common_semi_cb(cs, -1, err);
     common_semi_set_ret(cs, size);
-    errno = err;
-    set_swi_errno(cs, -1);
 }
 
 static int common_semi_open_guestfd;
@@ -362,64 +348,32 @@ static void
 common_semi_open_cb(CPUState *cs, target_ulong ret, target_ulong err)
 {
     if (ret == (target_ulong)-1) {
-        errno = err;
-        set_swi_errno(cs, -1);
         dealloc_guestfd(common_semi_open_guestfd);
     } else {
         associate_guestfd(common_semi_open_guestfd, ret);
         ret = common_semi_open_guestfd;
     }
-    common_semi_set_ret(cs, ret);
-}
-
-static target_ulong
-common_semi_gdb_syscall(CPUState *cs, gdb_syscall_complete_cb cb,
-                        const char *fmt, ...)
-{
-    va_list va;
-
-    va_start(va, fmt);
-    gdb_do_syscallv(cb, fmt, va);
-    va_end(va);
-
-    /*
-     * FIXME: in softmmu mode, the gdbstub will schedule our callback
-     * to occur, but will not actually call it to complete the syscall
-     * until after this function has returned and we are back in the
-     * CPU main loop. Therefore callers to this function must not
-     * do anything with its return value, because it is not necessarily
-     * the result of the syscall, but could just be the old value of X0.
-     * The only thing safe to do with this is that the callers of
-     * do_common_semihosting() will write it straight back into X0.
-     * (In linux-user mode, the callback will have happened before
-     * gdb_do_syscallv() returns.)
-     *
-     * We should tidy this up so neither this function nor
-     * do_common_semihosting() return a value, so the mistake of
-     * doing something with the return value is not possible to make.
-     */
-
-    return common_semi_arg(cs, 0);
+    common_semi_cb(cs, ret, err);
 }
 
 /*
  * Types for functions implementing various semihosting calls
  * for specific types of guest file descriptor. These must all
- * do the work and return the required return value for the guest,
- * setting the guest errno if appropriate.
+ * do the work and return the required return value to the guest
+ * via common_semi_cb.
  */
-typedef uint32_t sys_closefn(CPUState *cs, GuestFD *gf);
-typedef uint32_t sys_writefn(CPUState *cs, GuestFD *gf,
-                             target_ulong buf, uint32_t len);
-typedef uint32_t sys_readfn(CPUState *cs, GuestFD *gf,
-                            target_ulong buf, uint32_t len);
-typedef uint32_t sys_isattyfn(CPUState *cs, GuestFD *gf);
-typedef uint32_t sys_seekfn(CPUState *cs, GuestFD *gf,
-                            target_ulong offset);
-typedef uint32_t sys_flenfn(CPUState *cs, GuestFD *gf);
+typedef void sys_closefn(CPUState *cs, GuestFD *gf);
+typedef void sys_writefn(CPUState *cs, GuestFD *gf,
+                         target_ulong buf, uint32_t len);
+typedef void sys_readfn(CPUState *cs, GuestFD *gf,
+                        target_ulong buf, uint32_t len);
+typedef void sys_isattyfn(CPUState *cs, GuestFD *gf);
+typedef void sys_seekfn(CPUState *cs, GuestFD *gf, target_ulong offset);
+typedef void sys_flenfn(CPUState *cs, GuestFD *gf);
 
-static uint32_t host_closefn(CPUState *cs, GuestFD *gf)
+static void host_closefn(CPUState *cs, GuestFD *gf)
 {
+    int ret;
     /*
      * Only close the underlying host fd if it's one we opened on behalf
      * of the guest in SYS_OPEN.
@@ -427,113 +381,106 @@ static uint32_t host_closefn(CPUState *cs, GuestFD *gf)
     if (gf->hostfd == STDIN_FILENO ||
         gf->hostfd == STDOUT_FILENO ||
         gf->hostfd == STDERR_FILENO) {
-        return 0;
+        ret = 0;
+    } else {
+        ret = close(gf->hostfd);
     }
-    return set_swi_errno(cs, close(gf->hostfd));
+    common_semi_cb(cs, ret, ret ? errno : 0);
 }
 
-static uint32_t host_writefn(CPUState *cs, GuestFD *gf,
-                             target_ulong buf, uint32_t len)
+static void host_writefn(CPUState *cs, GuestFD *gf,
+                         target_ulong buf, uint32_t len)
 {
     CPUArchState *env = cs->env_ptr;
-    uint32_t ret;
+    uint32_t ret = 0;
     char *s = lock_user(VERIFY_READ, buf, len, 1);
     (void) env; /* Used in arm softmmu lock_user implicitly */
-    if (!s) {
-        /* Return bytes not written on error */
-        return len;
+    if (s) {
+        ret = write(gf->hostfd, s, len);
+        unlock_user(s, buf, 0);
+        if (ret == (uint32_t)-1) {
+            ret = 0;
+        }
     }
-    ret = set_swi_errno(cs, write(gf->hostfd, s, len));
-    unlock_user(s, buf, 0);
-    if (ret == (uint32_t)-1) {
-        ret = 0;
-    }
-    /* Return bytes not written */
-    return len - ret;
+    /* Return bytes not written, on error as well. */
+    common_semi_cb(cs, len - ret, 0);
 }
 
-static uint32_t host_readfn(CPUState *cs, GuestFD *gf,
-                            target_ulong buf, uint32_t len)
+static void host_readfn(CPUState *cs, GuestFD *gf,
+                        target_ulong buf, uint32_t len)
 {
     CPUArchState *env = cs->env_ptr;
-    uint32_t ret;
+    uint32_t ret = 0;
     char *s = lock_user(VERIFY_WRITE, buf, len, 0);
     (void) env; /* Used in arm softmmu lock_user implicitly */
-    if (!s) {
-        /* return bytes not read */
-        return len;
+    if (s) {
+        do {
+            ret = read(gf->hostfd, s, len);
+        } while (ret == -1 && errno == EINTR);
+        unlock_user(s, buf, len);
+        if (ret == (uint32_t)-1) {
+            ret = 0;
+        }
     }
-    do {
-        ret = set_swi_errno(cs, read(gf->hostfd, s, len));
-    } while (ret == -1 && errno == EINTR);
-    unlock_user(s, buf, len);
-    if (ret == (uint32_t)-1) {
-        ret = 0;
-    }
-    /* Return bytes not read */
-    return len - ret;
+    /* Return bytes not read, on error as well. */
+    common_semi_cb(cs, len - ret, 0);
 }
 
-static uint32_t host_isattyfn(CPUState *cs, GuestFD *gf)
+static void host_isattyfn(CPUState *cs, GuestFD *gf)
 {
-    return isatty(gf->hostfd);
+    common_semi_cb(cs, isatty(gf->hostfd), 0);
 }
 
-static uint32_t host_seekfn(CPUState *cs, GuestFD *gf, target_ulong offset)
+static void host_seekfn(CPUState *cs, GuestFD *gf, target_ulong offset)
 {
-    uint32_t ret = set_swi_errno(cs, lseek(gf->hostfd, offset, SEEK_SET));
-    if (ret == (uint32_t)-1) {
-        return -1;
-    }
-    return 0;
+    off_t ret = lseek(gf->hostfd, offset, SEEK_SET);
+    common_semi_cb(cs, ret, ret == -1 ? errno : 0);
 }
 
-static uint32_t host_flenfn(CPUState *cs, GuestFD *gf)
+static void host_flenfn(CPUState *cs, GuestFD *gf)
 {
     struct stat buf;
-    uint32_t ret = set_swi_errno(cs, fstat(gf->hostfd, &buf));
-    if (ret == (uint32_t)-1) {
-        return -1;
+
+    if (fstat(gf->hostfd, &buf)) {
+        common_semi_cb(cs, -1, errno);
+    } else {
+        common_semi_cb(cs, buf.st_size, 0);
     }
-    return buf.st_size;
 }
 
-static uint32_t gdb_closefn(CPUState *cs, GuestFD *gf)
+static void gdb_closefn(CPUState *cs, GuestFD *gf)
 {
-    return common_semi_gdb_syscall(cs, common_semi_cb, "close,%x", gf->hostfd);
+    gdb_do_syscall(common_semi_cb, "close,%x", gf->hostfd);
 }
 
-static uint32_t gdb_writefn(CPUState *cs, GuestFD *gf,
-                            target_ulong buf, uint32_t len)
+static void gdb_writefn(CPUState *cs, GuestFD *gf,
+                        target_ulong buf, uint32_t len)
 {
     common_semi_syscall_len = len;
-    return common_semi_gdb_syscall(cs, common_semi_cb, "write,%x,%x,%x",
-                                   gf->hostfd, buf, len);
+    gdb_do_syscall(common_semi_cb, "write,%x,%x,%x", gf->hostfd, buf, len);
 }
 
-static uint32_t gdb_readfn(CPUState *cs, GuestFD *gf,
-                           target_ulong buf, uint32_t len)
+static void gdb_readfn(CPUState *cs, GuestFD *gf,
+                       target_ulong buf, uint32_t len)
 {
     common_semi_syscall_len = len;
-    return common_semi_gdb_syscall(cs, common_semi_cb, "read,%x,%x,%x",
-                                   gf->hostfd, buf, len);
+    gdb_do_syscall(common_semi_cb, "read,%x,%x,%x", gf->hostfd, buf, len);
 }
 
-static uint32_t gdb_isattyfn(CPUState *cs, GuestFD *gf)
+static void gdb_isattyfn(CPUState *cs, GuestFD *gf)
 {
-    return common_semi_gdb_syscall(cs, common_semi_cb, "isatty,%x", gf->hostfd);
+    gdb_do_syscall(common_semi_cb, "isatty,%x", gf->hostfd);
 }
 
-static uint32_t gdb_seekfn(CPUState *cs, GuestFD *gf, target_ulong offset)
+static void gdb_seekfn(CPUState *cs, GuestFD *gf, target_ulong offset)
 {
-    return common_semi_gdb_syscall(cs, common_semi_cb, "lseek,%x,%x,0",
-                                   gf->hostfd, offset);
+    gdb_do_syscall(common_semi_cb, "lseek,%x,%x,0", gf->hostfd, offset);
 }
 
-static uint32_t gdb_flenfn(CPUState *cs, GuestFD *gf)
+static void gdb_flenfn(CPUState *cs, GuestFD *gf)
 {
-    return common_semi_gdb_syscall(cs, common_semi_flen_cb, "fstat,%x,%x",
-                                   gf->hostfd, common_semi_flen_buf(cs));
+    gdb_do_syscall(common_semi_flen_cb, "fstat,%x,%x",
+                   gf->hostfd, common_semi_flen_buf(cs));
 }
 
 #define SHFB_MAGIC_0 0x53
@@ -553,63 +500,57 @@ static const uint8_t featurefile_data[] = {
     SH_EXT_EXIT_EXTENDED | SH_EXT_STDOUT_STDERR, /* Feature byte 0 */
 };
 
-static uint32_t staticfile_closefn(CPUState *cs, GuestFD *gf)
+static void staticfile_closefn(CPUState *cs, GuestFD *gf)
 {
     /* Nothing to do */
-    return 0;
+    common_semi_cb(cs, 0, 0);
 }
 
-static uint32_t staticfile_writefn(CPUState *cs, GuestFD *gf,
-                                    target_ulong buf, uint32_t len)
+static void staticfile_writefn(CPUState *cs, GuestFD *gf,
+                               target_ulong buf, uint32_t len)
 {
     /* This fd can never be open for writing */
-
-    errno = EBADF;
-    return set_swi_errno(cs, -1);
+    common_semi_cb(cs, -1, EBADF);
 }
 
-static uint32_t staticfile_readfn(CPUState *cs, GuestFD *gf,
-                                   target_ulong buf, uint32_t len)
+static void staticfile_readfn(CPUState *cs, GuestFD *gf,
+                              target_ulong buf, uint32_t len)
 {
     CPUArchState *env = cs->env_ptr;
-    uint32_t i;
+    uint32_t i = 0;
     char *s;
 
     (void) env; /* Used in arm softmmu lock_user implicitly */
     s = lock_user(VERIFY_WRITE, buf, len, 0);
-    if (!s) {
-        return len;
-    }
-
-    for (i = 0; i < len; i++) {
-        if (gf->staticfile.off >= gf->staticfile.len) {
-            break;
+    if (s) {
+        for (i = 0; i < len; i++) {
+            if (gf->staticfile.off >= gf->staticfile.len) {
+                break;
+            }
+            s[i] = gf->staticfile.data[gf->staticfile.off];
+            gf->staticfile.off++;
         }
-        s[i] = gf->staticfile.data[gf->staticfile.off];
-        gf->staticfile.off++;
+        unlock_user(s, buf, len);
     }
 
-    unlock_user(s, buf, len);
-
     /* Return number of bytes not read */
-    return len - i;
+    common_semi_cb(cs, len - i, 0);
 }
 
-static uint32_t staticfile_isattyfn(CPUState *cs, GuestFD *gf)
+static void staticfile_isattyfn(CPUState *cs, GuestFD *gf)
 {
-    return 0;
+    common_semi_cb(cs, 0, 0);
 }
 
-static uint32_t staticfile_seekfn(CPUState *cs, GuestFD *gf,
-                                   target_ulong offset)
+static void staticfile_seekfn(CPUState *cs, GuestFD *gf, target_ulong offset)
 {
     gf->staticfile.off = offset;
-    return 0;
+    common_semi_cb(cs, 0, 0);
 }
 
-static uint32_t staticfile_flenfn(CPUState *cs, GuestFD *gf)
+static void staticfile_flenfn(CPUState *cs, GuestFD *gf)
 {
-    return gf->staticfile.len;
+    common_semi_cb(cs, gf->staticfile.len, 0);
 }
 
 typedef struct GuestFDFunctions {
@@ -668,13 +609,13 @@ static inline bool is_64bit_semihosting(CPUArchState *env)
 #define GET_ARG(n) do {                                 \
     if (is_64bit_semihosting(env)) {                    \
         if (get_user_u64(arg ## n, args + (n) * 8)) {   \
-            errno = EFAULT;                             \
-            return set_swi_errno(cs, -1);               \
+            common_semi_cb(cs, -1, EFAULT);             \
+            return;                                     \
         }                                               \
     } else {                                            \
         if (get_user_u32(arg ## n, args + (n) * 4)) {   \
-            errno = EFAULT;                             \
-            return set_swi_errno(cs, -1);              \
+            common_semi_cb(cs, -1, EFAULT);             \
+            return;                                     \
         }                                               \
     }                                                   \
 } while (0)
@@ -694,7 +635,7 @@ static inline bool is_64bit_semihosting(CPUArchState *env)
  * leave the register unchanged. We use 0xdeadbeef as the return value
  * when there isn't a defined return value for the call.
  */
-target_ulong do_common_semihosting(CPUState *cs)
+void do_common_semihosting(CPUState *cs)
 {
     CPUArchState *env = cs->env_ptr;
     target_ulong args;
@@ -714,32 +655,23 @@ target_ulong do_common_semihosting(CPUState *cs)
     switch (nr) {
     case TARGET_SYS_OPEN:
     {
-        int guestfd;
+        int ret, err = 0;
+        int hostfd;
 
         GET_ARG(0);
         GET_ARG(1);
         GET_ARG(2);
         s = lock_user_string(arg0);
         if (!s) {
-            errno = EFAULT;
-            return set_swi_errno(cs, -1);
+            goto do_fault;
         }
         if (arg1 >= 12) {
             unlock_user(s, arg0, 0);
-            errno = EINVAL;
-            return set_swi_errno(cs, -1);
-        }
-
-        guestfd = alloc_guestfd();
-        if (guestfd < 0) {
-            unlock_user(s, arg0, 0);
-            errno = EMFILE;
-            return set_swi_errno(cs, -1);
+            common_semi_cb(cs, -1, EINVAL);
+            break;
         }
 
         if (strcmp(s, ":tt") == 0) {
-            int result_fileno;
-
             /*
              * We implement SH_EXT_STDOUT_STDERR, so:
              *  open for read == stdin
@@ -747,63 +679,67 @@ target_ulong do_common_semihosting(CPUState *cs)
              *  open for append == stderr
              */
             if (arg1 < 4) {
-                result_fileno = STDIN_FILENO;
+                hostfd = STDIN_FILENO;
             } else if (arg1 < 8) {
-                result_fileno = STDOUT_FILENO;
+                hostfd = STDOUT_FILENO;
             } else {
-                result_fileno = STDERR_FILENO;
+                hostfd = STDERR_FILENO;
             }
-            associate_guestfd(guestfd, result_fileno);
-            unlock_user(s, arg0, 0);
-            return guestfd;
-        }
-        if (strcmp(s, ":semihosting-features") == 0) {
-            unlock_user(s, arg0, 0);
+            ret = alloc_guestfd();
+            associate_guestfd(ret, hostfd);
+        } else if (strcmp(s, ":semihosting-features") == 0) {
             /* We must fail opens for modes other than 0 ('r') or 1 ('rb') */
             if (arg1 != 0 && arg1 != 1) {
-                dealloc_guestfd(guestfd);
-                errno = EACCES;
-                return set_swi_errno(cs, -1);
-            }
-            staticfile_guestfd(guestfd, featurefile_data,
-                               sizeof(featurefile_data));
-            return guestfd;
-        }
-
-        if (use_gdb_syscalls()) {
-            common_semi_open_guestfd = guestfd;
-            ret = common_semi_gdb_syscall(cs, common_semi_open_cb,
-                                          "open,%s,%x,1a4", arg0, (int)arg2 + 1,
-                                          gdb_open_modeflags[arg1]);
-        } else {
-            ret = set_swi_errno(cs, open(s, open_modeflags[arg1], 0644));
-            if (ret == (uint32_t)-1) {
-                dealloc_guestfd(guestfd);
+                ret = -1;
+                err = EACCES;
             } else {
-                associate_guestfd(guestfd, ret);
-                ret = guestfd;
+                ret = alloc_guestfd();
+                staticfile_guestfd(ret, featurefile_data,
+                                   sizeof(featurefile_data));
+            }
+        } else if (use_gdb_syscalls()) {
+            unlock_user(s, arg0, 0);
+            common_semi_open_guestfd = alloc_guestfd();
+            gdb_do_syscall(common_semi_open_cb,
+                           "open,%s,%x,1a4", arg0, (int)arg2 + 1,
+                           gdb_open_modeflags[arg1]);
+            break;
+        } else {
+            hostfd = open(s, open_modeflags[arg1], 0644);
+            if (hostfd < 0) {
+                ret = -1;
+                err = errno;
+            } else {
+                ret = alloc_guestfd();
+                associate_guestfd(ret, hostfd);
             }
         }
         unlock_user(s, arg0, 0);
-        return ret;
+        common_semi_cb(cs, ret, err);
+        break;
     }
+
     case TARGET_SYS_CLOSE:
         GET_ARG(0);
 
         gf = get_guestfd(arg0);
         if (!gf) {
-            errno = EBADF;
-            return set_swi_errno(cs, -1);
+            goto do_badf;
         }
-
-        ret = guestfd_fns[gf->type].closefn(cs, gf);
+        guestfd_fns[gf->type].closefn(cs, gf);
         dealloc_guestfd(arg0);
-        return ret;
+        break;
+
     case TARGET_SYS_WRITEC:
         qemu_semihosting_console_outc(cs->env_ptr, args);
-        return 0xdeadbeef;
+        common_semi_set_ret(cs, 0xdeadbeef);
+        break;
+
     case TARGET_SYS_WRITE0:
-        return qemu_semihosting_console_outs(cs->env_ptr, args);
+        ret = qemu_semihosting_console_outs(cs->env_ptr, args);
+        common_semi_set_ret(cs, ret);
+        break;
+
     case TARGET_SYS_WRITE:
         GET_ARG(0);
         GET_ARG(1);
@@ -812,11 +748,11 @@ target_ulong do_common_semihosting(CPUState *cs)
 
         gf = get_guestfd(arg0);
         if (!gf) {
-            errno = EBADF;
-            return set_swi_errno(cs, -1);
+            goto do_badf;
         }
+        guestfd_fns[gf->type].writefn(cs, gf, arg1, len);
+        break;
 
-        return guestfd_fns[gf->type].writefn(cs, gf, arg1, len);
     case TARGET_SYS_READ:
         GET_ARG(0);
         GET_ARG(1);
@@ -825,129 +761,150 @@ target_ulong do_common_semihosting(CPUState *cs)
 
         gf = get_guestfd(arg0);
         if (!gf) {
-            errno = EBADF;
-            return set_swi_errno(cs, -1);
+            goto do_badf;
         }
+        guestfd_fns[gf->type].readfn(cs, gf, arg1, len);
+        break;
 
-        return guestfd_fns[gf->type].readfn(cs, gf, arg1, len);
     case TARGET_SYS_READC:
-        return qemu_semihosting_console_inc(cs->env_ptr);
+        ret = qemu_semihosting_console_inc(cs->env_ptr);
+        common_semi_set_ret(cs, ret);
+        break;
+
     case TARGET_SYS_ISERROR:
         GET_ARG(0);
-        return (target_long) arg0 < 0 ? 1 : 0;
+        common_semi_set_ret(cs, (target_long)arg0 < 0);
+        break;
+
     case TARGET_SYS_ISTTY:
         GET_ARG(0);
 
         gf = get_guestfd(arg0);
         if (!gf) {
-            errno = EBADF;
-            return set_swi_errno(cs, -1);
+            goto do_badf;
         }
+        guestfd_fns[gf->type].isattyfn(cs, gf);
+        break;
 
-        return guestfd_fns[gf->type].isattyfn(cs, gf);
     case TARGET_SYS_SEEK:
         GET_ARG(0);
         GET_ARG(1);
 
         gf = get_guestfd(arg0);
         if (!gf) {
-            errno = EBADF;
-            return set_swi_errno(cs, -1);
+            goto do_badf;
         }
+        guestfd_fns[gf->type].seekfn(cs, gf, arg1);
+        break;
 
-        return guestfd_fns[gf->type].seekfn(cs, gf, arg1);
     case TARGET_SYS_FLEN:
         GET_ARG(0);
 
         gf = get_guestfd(arg0);
         if (!gf) {
-            errno = EBADF;
-            return set_swi_errno(cs, -1);
+            goto do_badf;
         }
+        guestfd_fns[gf->type].flenfn(cs, gf);
+        break;
 
-        return guestfd_fns[gf->type].flenfn(cs, gf);
     case TARGET_SYS_TMPNAM:
+    {
+        int len;
+        char *p;
+
         GET_ARG(0);
         GET_ARG(1);
         GET_ARG(2);
-        if (asprintf(&s, "/tmp/qemu-%x%02x", getpid(),
-                     (int) (arg1 & 0xff)) < 0) {
-            return -1;
-        }
-        ul_ret = (target_ulong) -1;
-
+        len = asprintf(&s, "/tmp/qemu-%x%02x", getpid(), (int)arg1 & 0xff);
         /* Make sure there's enough space in the buffer */
-        if (strlen(s) < arg2) {
-            char *output = lock_user(VERIFY_WRITE, arg0, arg2, 0);
-            strcpy(output, s);
-            unlock_user(output, arg0, arg2);
-            ul_ret = 0;
+        if (len < 0 || len >= arg2) {
+            common_semi_set_ret(cs, -1);
+            break;
         }
+        p = lock_user(VERIFY_WRITE, arg0, len, 0);
+        if (!p) {
+            goto do_fault;
+        }
+        memcpy(p, s, len + 1);
+        unlock_user(p, arg0, len);
         free(s);
-        return ul_ret;
+        common_semi_set_ret(cs, 0);
+        break;
+    }
+
     case TARGET_SYS_REMOVE:
         GET_ARG(0);
         GET_ARG(1);
         if (use_gdb_syscalls()) {
-            ret = common_semi_gdb_syscall(cs, common_semi_cb, "unlink,%s",
-                                          arg0, (int)arg1 + 1);
-        } else {
-            s = lock_user_string(arg0);
-            if (!s) {
-                errno = EFAULT;
-                return set_swi_errno(cs, -1);
-            }
-            ret =  set_swi_errno(cs, remove(s));
-            unlock_user(s, arg0, 0);
+            gdb_do_syscall(common_semi_cb, "unlink,%s",
+                           arg0, (int)arg1 + 1);
+            break;
         }
-        return ret;
+        s = lock_user_string(arg0);
+        if (!s) {
+            goto do_fault;
+        }
+        ret = remove(s);
+        unlock_user(s, arg0, 0);
+        common_semi_cb(cs, ret, ret ? errno : 0);
+        break;
+
     case TARGET_SYS_RENAME:
         GET_ARG(0);
         GET_ARG(1);
         GET_ARG(2);
         GET_ARG(3);
         if (use_gdb_syscalls()) {
-            return common_semi_gdb_syscall(cs, common_semi_cb, "rename,%s,%s",
-                                           arg0, (int)arg1 + 1, arg2,
-                                           (int)arg3 + 1);
+            gdb_do_syscall(common_semi_cb, "rename,%s,%s",
+                           arg0, (int)arg1 + 1, arg2, (int)arg3 + 1);
         } else {
             char *s2;
+
             s = lock_user_string(arg0);
-            s2 = lock_user_string(arg2);
-            if (!s || !s2) {
-                errno = EFAULT;
-                ret = set_swi_errno(cs, -1);
-            } else {
-                ret = set_swi_errno(cs, rename(s, s2));
+            if (!s) {
+                goto do_fault;
             }
-            if (s2)
-                unlock_user(s2, arg2, 0);
-            if (s)
+            s2 = lock_user_string(arg2);
+            if (!s2) {
                 unlock_user(s, arg0, 0);
-            return ret;
+                goto do_fault;
+            }
+            ret = rename(s, s2);
+            unlock_user(s2, arg2, 0);
+            unlock_user(s, arg0, 0);
+            common_semi_cb(cs, ret, ret ? errno : 0);
         }
+        break;
+
     case TARGET_SYS_CLOCK:
-        return clock() / (CLOCKS_PER_SEC / 100);
+        common_semi_set_ret(cs, clock() / (CLOCKS_PER_SEC / 100));
+        break;
+
     case TARGET_SYS_TIME:
-        return set_swi_errno(cs, time(NULL));
+        ul_ret = time(NULL);
+        common_semi_cb(cs, ul_ret, ul_ret == -1 ? errno : 0);
+        break;
+
     case TARGET_SYS_SYSTEM:
         GET_ARG(0);
         GET_ARG(1);
         if (use_gdb_syscalls()) {
-            return common_semi_gdb_syscall(cs, common_semi_cb, "system,%s",
-                                           arg0, (int)arg1 + 1);
-        } else {
-            s = lock_user_string(arg0);
-            if (!s) {
-                errno = EFAULT;
-                return set_swi_errno(cs, -1);
-            }
-            ret = set_swi_errno(cs, system(s));
-            unlock_user(s, arg0, 0);
-            return ret;
+            gdb_do_syscall(common_semi_cb, "system,%s", arg0, (int)arg1 + 1);
+            break;
         }
+        s = lock_user_string(arg0);
+        if (!s) {
+            goto do_fault;
+        }
+        ret = system(s);
+        unlock_user(s, arg0, 0);
+        common_semi_cb(cs, ret, ret == -1 ? errno : 0);
+        break;
+
     case TARGET_SYS_ERRNO:
-        return get_swi_errno(cs);
+        common_semi_set_ret(cs, get_swi_errno(cs));
+        break;
+
     case TARGET_SYS_GET_CMDLINE:
         {
             /* Build a command-line from the original argv.
@@ -998,22 +955,20 @@ target_ulong do_common_semihosting(CPUState *cs)
 
             if (output_size > input_size) {
                 /* Not enough space to store command-line arguments.  */
-                errno = E2BIG;
-                return set_swi_errno(cs, -1);
+                common_semi_cb(cs, -1, E2BIG);
+                break;
             }
 
             /* Adjust the command-line length.  */
             if (SET_ARG(1, output_size - 1)) {
                 /* Couldn't write back to argument block */
-                errno = EFAULT;
-                return set_swi_errno(cs, -1);
+                goto do_fault;
             }
 
             /* Lock the buffer on the ARM side.  */
             output_buffer = lock_user(VERIFY_WRITE, arg0, output_size, 0);
             if (!output_buffer) {
-                errno = EFAULT;
-                return set_swi_errno(cs, -1);
+                goto do_fault;
             }
 
             /* Copy the command-line arguments.  */
@@ -1028,9 +983,8 @@ target_ulong do_common_semihosting(CPUState *cs)
 
             if (copy_from_user(output_buffer, ts->info->arg_start,
                                output_size)) {
-                errno = EFAULT;
-                status = set_swi_errno(cs, -1);
-                goto out;
+                unlock_user(output_buffer, arg0, 0);
+                goto do_fault;
             }
 
             /* Separate arguments by white spaces.  */
@@ -1043,9 +997,10 @@ target_ulong do_common_semihosting(CPUState *cs)
 #endif
             /* Unlock the buffer on the ARM side.  */
             unlock_user(output_buffer, arg0, output_size);
-
-            return status;
+            common_semi_cb(cs, status, 0);
         }
+        break;
+
     case TARGET_SYS_HEAPINFO:
         {
             target_ulong retvals[4];
@@ -1102,12 +1057,13 @@ target_ulong do_common_semihosting(CPUState *cs)
 
                 if (fail) {
                     /* Couldn't write back to argument block */
-                    errno = EFAULT;
-                    return set_swi_errno(cs, -1);
+                    goto do_fault;
                 }
             }
-            return 0;
+            common_semi_set_ret(cs, 0);
         }
+        break;
+
     case TARGET_SYS_EXIT:
     case TARGET_SYS_EXIT_EXTENDED:
         if (common_semi_sys_exit_extended(cs, nr)) {
@@ -1137,6 +1093,7 @@ target_ulong do_common_semihosting(CPUState *cs)
         }
         gdb_exit(ret);
         exit(ret);
+
     case TARGET_SYS_ELAPSED:
         elapsed = get_clock() - clock_start;
         if (sizeof(target_ulong) == 8) {
@@ -1145,10 +1102,14 @@ target_ulong do_common_semihosting(CPUState *cs)
             SET_ARG(0, (uint32_t) elapsed);
             SET_ARG(1, (uint32_t) (elapsed >> 32));
         }
-        return 0;
+        common_semi_set_ret(cs, 0);
+        break;
+
     case TARGET_SYS_TICKFREQ:
         /* qemu always uses nsec */
-        return 1000000000;
+        common_semi_set_ret(cs, 1000000000);
+        break;
+
     case TARGET_SYS_SYNCCACHE:
         /*
          * Clean the D-cache and invalidate the I-cache for the specified
@@ -1157,16 +1118,24 @@ target_ulong do_common_semihosting(CPUState *cs)
          */
 #ifdef TARGET_ARM
         if (is_a64(cs->env_ptr)) {
-            return 0;
+            common_semi_set_ret(cs, 0);
+            break;
         }
 #endif
 #ifdef TARGET_RISCV
-        return 0;
+        common_semi_set_ret(cs, 0);
 #endif
         /* fall through -- invalid for A32/T32 */
     default:
         fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr);
         cpu_dump_state(cs, stderr, 0);
         abort();
+
+    do_badf:
+        common_semi_cb(cs, -1, EBADF);
+        break;
+    do_fault:
+        common_semi_cb(cs, -1, EFAULT);
+        break;
     }
 }
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 5a244c3ed9..4981a22821 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -10195,13 +10195,13 @@ static void handle_semihosting(CPUState *cs)
         qemu_log_mask(CPU_LOG_INT,
                       "...handling as semihosting call 0x%" PRIx64 "\n",
                       env->xregs[0]);
-        env->xregs[0] = do_common_semihosting(cs);
+        do_common_semihosting(cs);
         env->pc += 4;
     } else {
         qemu_log_mask(CPU_LOG_INT,
                       "...handling as semihosting call 0x%x\n",
                       env->regs[0]);
-        env->regs[0] = do_common_semihosting(cs);
+        do_common_semihosting(cs);
         env->regs[15] += env->thumb ? 2 : 4;
     }
 }
diff --git a/target/arm/m_helper.c b/target/arm/m_helper.c
index a740c3e160..308610f6b4 100644
--- a/target/arm/m_helper.c
+++ b/target/arm/m_helper.c
@@ -2373,7 +2373,7 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
                       "...handling as semihosting call 0x%x\n",
                       env->regs[0]);
 #ifdef CONFIG_TCG
-        env->regs[0] = do_common_semihosting(cs);
+        do_common_semihosting(cs);
 #else
         g_assert_not_reached();
 #endif
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index e1aa4f2097..55105cb0cc 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -1345,7 +1345,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
 
     if  (cause == RISCV_EXCP_SEMIHOST) {
         if (env->priv >= PRV_S) {
-            env->gpr[xA0] = do_common_semihosting(cs);
+            do_common_semihosting(cs);
             env->pc += 4;
             return;
         }
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 10/74] semihosting: Adjust error checking in common_semi_cb
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (8 preceding siblings ...)
  2022-05-03 19:47 ` [PATCH v2 09/74] semihosting: Return void from do_common_semihosting Richard Henderson
@ 2022-05-03 19:47 ` Richard Henderson
  2022-05-03 19:47 ` [PATCH v2 11/74] semihosting: Move common-semi.h to include/semihosting/ Richard Henderson
                   ` (63 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:47 UTC (permalink / raw)
  To: qemu-devel

The err parameter is non-zero if and only if an error occured.
Use this instead of ret == -1 for determining if we need to
update the saved errno.

This fixes the errno setting of SYS_ISTTY, which returns 0 on
error, not -1.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 semihosting/arm-compat-semi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index 7030dfd587..18664b1c47 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -276,7 +276,7 @@ static target_ulong common_semi_syscall_len;
 
 static void common_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
 {
-    if (ret == (target_ulong)-1) {
+    if (err) {
 #ifdef CONFIG_USER_ONLY
         TaskState *ts = cs->opaque;
         ts->swi_errno = err;
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 11/74] semihosting: Move common-semi.h to include/semihosting/
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (9 preceding siblings ...)
  2022-05-03 19:47 ` [PATCH v2 10/74] semihosting: Adjust error checking in common_semi_cb Richard Henderson
@ 2022-05-03 19:47 ` Richard Henderson
  2022-05-03 19:47 ` [PATCH v2 12/74] include/exec: Move gdb open flags to gdbstub.h Richard Henderson
                   ` (62 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:47 UTC (permalink / raw)
  To: qemu-devel

This header is not private to the top-level semihosting directory,
so place it in the public include directory.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 {semihosting => include/semihosting}/common-semi.h | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename {semihosting => include/semihosting}/common-semi.h (100%)

diff --git a/semihosting/common-semi.h b/include/semihosting/common-semi.h
similarity index 100%
rename from semihosting/common-semi.h
rename to include/semihosting/common-semi.h
-- 
2.34.1



^ permalink raw reply	[flat|nested] 92+ messages in thread

* [PATCH v2 12/74] include/exec: Move gdb open flags to gdbstub.h
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (10 preceding siblings ...)
  2022-05-03 19:47 ` [PATCH v2 11/74] semihosting: Move common-semi.h to include/semihosting/ Richard Henderson
@ 2022-05-03 19:47 ` Richard Henderson
  2022-05-03 19:47 ` [PATCH v2 13/74] include/exec: Move gdb_stat and gdb_timeval " Richard Henderson
                   ` (61 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:47 UTC (permalink / raw)
  To: qemu-devel

There were 3 copies of these flags.  Place them in the
file with gdb_do_syscall, with which they belong.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/exec/gdbstub.h        | 10 ++++++++++
 semihosting/arm-compat-semi.c |  8 --------
 target/m68k/m68k-semi.c       |  8 --------
 target/nios2/nios2-semi.c     |  8 --------
 4 files changed, 10 insertions(+), 24 deletions(-)

diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index c35d7334b4..2aaba9c723 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -10,6 +10,16 @@
 #define GDB_WATCHPOINT_READ      3
 #define GDB_WATCHPOINT_ACCESS    4
 
+/* For gdb file i/o remote protocol open flags. */
+#define GDB_O_BINARY  0
+#define GDB_O_RDONLY  0
+#define GDB_O_WRONLY  1
+#define GDB_O_RDWR    2
+#define GDB_O_APPEND  8
+#define GDB_O_CREAT   0x200
+#define GDB_O_TRUNC   0x400
+#define GDB_O_EXCL    0x800
+
 #ifdef NEED_CPU_H
 #include "cpu.h"
 
diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index 18664b1c47..a1fc4ea039 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -86,14 +86,6 @@
 #define O_BINARY 0
 #endif
 
-#define GDB_O_RDONLY  0x000
-#define GDB_O_WRONLY  0x001
-#define GDB_O_RDWR    0x002
-#define GDB_O_APPEND  0x008
-#define GDB_O_CREAT   0x200
-#define GDB_O_TRUNC   0x400
-#define GDB_O_BINARY  0
-
 static int gdb_open_modeflags[12] = {
     GDB_O_RDONLY,
     GDB_O_RDONLY | GDB_O_BINARY,
diff --git a/target/m68k/m68k-semi.c b/target/m68k/m68k-semi.c
index a31db38fc3..475a6b13b7 100644
--- a/target/m68k/m68k-semi.c
+++ b/target/m68k/m68k-semi.c
@@ -69,14 +69,6 @@ struct gdb_timeval {
   uint64_t tv_usec;   /* microsecond */
 } QEMU_PACKED;
 
-#define GDB_O_RDONLY   0x0
-#define GDB_O_WRONLY   0x1
-#define GDB_O_RDWR     0x2
-#define GDB_O_APPEND   0x8
-#define GDB_O_CREAT  0x200
-#define GDB_O_TRUNC  0x400
-#define GDB_O_EXCL   0x800
-
 static int translate_openflags(int flags)
 {
     int hf;
diff --git a/target/nios2/nios2-semi.c b/target/nios2/nios2-semi.c
index 373e6b9436..0eec1f9a1c 100644
--- a/target/nios2/nios2-semi.c
+++ b/target/nios2/nios2-semi.c
@@ -71,14 +71,6 @@ struct gdb_timeval {
   uint64_t tv_usec;   /* microsecond */
 } QEMU_PACKED;
 
-#define GDB_O_RDONLY   0x0
-#define GDB_O_WRONLY   0x1
-#define GDB_O_RDWR     0x2
-#define GDB_O_APPEND   0x8
-#define GDB_O_CREAT  0x200
-#define GDB_O_TRUNC  0x400
-#define GDB_O_EXCL   0x800
-
 static int translate_openflags(int flags)
 {
     int hf;
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 13/74] include/exec: Move gdb_stat and gdb_timeval to gdbstub.h
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (11 preceding siblings ...)
  2022-05-03 19:47 ` [PATCH v2 12/74] include/exec: Move gdb open flags to gdbstub.h Richard Henderson
@ 2022-05-03 19:47 ` Richard Henderson
  2022-05-03 19:47 ` [PATCH v2 14/74] include/exec: Define errno values in gdbstub.h Richard Henderson
                   ` (60 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:47 UTC (permalink / raw)
  To: qemu-devel

We have two copies of these structures, and require them
in semihosting/ going forward.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/exec/gdbstub.h    | 25 +++++++++++++++++++++++++
 target/m68k/m68k-semi.c   | 30 +++---------------------------
 target/nios2/nios2-semi.c | 30 +++---------------------------
 3 files changed, 31 insertions(+), 54 deletions(-)

diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index 2aaba9c723..33a262a5a3 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -20,6 +20,31 @@
 #define GDB_O_TRUNC   0x400
 #define GDB_O_EXCL    0x800
 
+/* For gdb file i/o stat/fstat. */
+typedef uint32_t gdb_mode_t;
+typedef uint32_t gdb_time_t;
+
+struct gdb_stat {
+  uint32_t    gdb_st_dev;     /* device */
+  uint32_t    gdb_st_ino;     /* inode */
+  gdb_mode_t  gdb_st_mode;    /* protection */
+  uint32_t    gdb_st_nlink;   /* number of hard links */
+  uint32_t    gdb_st_uid;     /* user ID of owner */
+  uint32_t    gdb_st_gid;     /* group ID of owner */
+  uint32_t    gdb_st_rdev;    /* device type (if inode device) */
+  uint64_t    gdb_st_size;    /* total size, in bytes */
+  uint64_t    gdb_st_blksize; /* blocksize for filesystem I/O */
+  uint64_t    gdb_st_blocks;  /* number of blocks allocated */
+  gdb_time_t  gdb_st_atime;   /* time of last access */
+  gdb_time_t  gdb_st_mtime;   /* time of last modification */
+  gdb_time_t  gdb_st_ctime;   /* time of last change */
+} QEMU_PACKED;
+
+struct gdb_timeval {
+  gdb_time_t tv_sec;  /* second */
+  uint64_t tv_usec;   /* microsecond */
+} QEMU_PACKED;
+
 #ifdef NEED_CPU_H
 #include "cpu.h"
 
diff --git a/target/m68k/m68k-semi.c b/target/m68k/m68k-semi.c
index 475a6b13b7..da0186f3ef 100644
--- a/target/m68k/m68k-semi.c
+++ b/target/m68k/m68k-semi.c
@@ -45,30 +45,6 @@
 #define HOSTED_ISATTY 12
 #define HOSTED_SYSTEM 13
 
-typedef uint32_t gdb_mode_t;
-typedef uint32_t gdb_time_t;
-
-struct m68k_gdb_stat {
-  uint32_t    gdb_st_dev;     /* device */
-  uint32_t    gdb_st_ino;     /* inode */
-  gdb_mode_t  gdb_st_mode;    /* protection */
-  uint32_t    gdb_st_nlink;   /* number of hard links */
-  uint32_t    gdb_st_uid;     /* user ID of owner */
-  uint32_t    gdb_st_gid;     /* group ID of owner */
-  uint32_t    gdb_st_rdev;    /* device type (if inode device) */
-  uint64_t    gdb_st_size;    /* total size, in bytes */
-  uint64_t    gdb_st_blksize; /* blocksize for filesystem I/O */
-  uint64_t    gdb_st_blocks;  /* number of blocks allocated */
-  gdb_time_t  gdb_st_atime;   /* time of last access */
-  gdb_time_t  gdb_st_mtime;   /* time of last modification */
-  gdb_time_t  gdb_st_ctime;   /* time of last change */
-} QEMU_PACKED;
-
-struct gdb_timeval {
-  gdb_time_t tv_sec;  /* second */
-  uint64_t tv_usec;   /* microsecond */
-} QEMU_PACKED;
-
 static int translate_openflags(int flags)
 {
     int hf;
@@ -90,9 +66,9 @@ static int translate_openflags(int flags)
 
 static void translate_stat(CPUM68KState *env, target_ulong addr, struct stat *s)
 {
-    struct m68k_gdb_stat *p;
+    struct gdb_stat *p;
 
-    if (!(p = lock_user(VERIFY_WRITE, addr, sizeof(struct m68k_gdb_stat), 0)))
+    if (!(p = lock_user(VERIFY_WRITE, addr, sizeof(struct gdb_stat), 0)))
         /* FIXME - should this return an error code? */
         return;
     p->gdb_st_dev = cpu_to_be32(s->st_dev);
@@ -114,7 +90,7 @@ static void translate_stat(CPUM68KState *env, target_ulong addr, struct stat *s)
     p->gdb_st_atime = cpu_to_be32(s->st_atime);
     p->gdb_st_mtime = cpu_to_be32(s->st_mtime);
     p->gdb_st_ctime = cpu_to_be32(s->st_ctime);
-    unlock_user(p, addr, sizeof(struct m68k_gdb_stat));
+    unlock_user(p, addr, sizeof(struct gdb_stat));
 }
 
 static void m68k_semi_return_u32(CPUM68KState *env, uint32_t ret, uint32_t err)
diff --git a/target/nios2/nios2-semi.c b/target/nios2/nios2-semi.c
index 0eec1f9a1c..3e504a6c5f 100644
--- a/target/nios2/nios2-semi.c
+++ b/target/nios2/nios2-semi.c
@@ -47,30 +47,6 @@
 #define HOSTED_ISATTY 12
 #define HOSTED_SYSTEM 13
 
-typedef uint32_t gdb_mode_t;
-typedef uint32_t gdb_time_t;
-
-struct nios2_gdb_stat {
-  uint32_t    gdb_st_dev;     /* device */
-  uint32_t    gdb_st_ino;     /* inode */
-  gdb_mode_t  gdb_st_mode;    /* protection */
-  uint32_t    gdb_st_nlink;   /* number of hard links */
-  uint32_t    gdb_st_uid;     /* user ID of owner */
-  uint32_t    gdb_st_gid;     /* group ID of owner */
-  uint32_t    gdb_st_rdev;    /* device type (if inode device) */
-  uint64_t    gdb_st_size;    /* total size, in bytes */
-  uint64_t    gdb_st_blksize; /* blocksize for filesystem I/O */
-  uint64_t    gdb_st_blocks;  /* number of blocks allocated */
-  gdb_time_t  gdb_st_atime;   /* time of last access */
-  gdb_time_t  gdb_st_mtime;   /* time of last modification */
-  gdb_time_t  gdb_st_ctime;   /* time of last change */
-} QEMU_PACKED;
-
-struct gdb_timeval {
-  gdb_time_t tv_sec;  /* second */
-  uint64_t tv_usec;   /* microsecond */
-} QEMU_PACKED;
-
 static int translate_openflags(int flags)
 {
     int hf;
@@ -102,9 +78,9 @@ static int translate_openflags(int flags)
 static bool translate_stat(CPUNios2State *env, target_ulong addr,
                            struct stat *s)
 {
-    struct nios2_gdb_stat *p;
+    struct gdb_stat *p;
 
-    p = lock_user(VERIFY_WRITE, addr, sizeof(struct nios2_gdb_stat), 0);
+    p = lock_user(VERIFY_WRITE, addr, sizeof(struct gdb_stat), 0);
 
     if (!p) {
         return false;
@@ -128,7 +104,7 @@ static bool translate_stat(CPUNios2State *env, target_ulong addr,
     p->gdb_st_atime = cpu_to_be32(s->st_atime);
     p->gdb_st_mtime = cpu_to_be32(s->st_mtime);
     p->gdb_st_ctime = cpu_to_be32(s->st_ctime);
-    unlock_user(p, addr, sizeof(struct nios2_gdb_stat));
+    unlock_user(p, addr, sizeof(struct gdb_stat));
     return true;
 }
 
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 14/74] include/exec: Define errno values in gdbstub.h
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (12 preceding siblings ...)
  2022-05-03 19:47 ` [PATCH v2 13/74] include/exec: Move gdb_stat and gdb_timeval " Richard Henderson
@ 2022-05-03 19:47 ` Richard Henderson
  2022-05-03 19:47 ` [PATCH v2 15/74] semihosting: Use struct gdb_stat in common_semi_flen_cb Richard Henderson
                   ` (59 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:47 UTC (permalink / raw)
  To: qemu-devel

Define constants for the errno values defined by the
gdb remote fileio protocol.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/exec/gdbstub.h | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index 33a262a5a3..0a6e0d6eeb 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -20,6 +20,28 @@
 #define GDB_O_TRUNC   0x400
 #define GDB_O_EXCL    0x800
 
+/* For gdb file i/o remove protocol errno values */
+#define GDB_EPERM           1
+#define GDB_ENOENT          2
+#define GDB_EINTR           4
+#define GDB_EBADF           9
+#define GDB_EACCES         13
+#define GDB_EFAULT         14
+#define GDB_EBUSY          16
+#define GDB_EEXIST         17
+#define GDB_ENODEV         19
+#define GDB_ENOTDIR        20
+#define GDB_EISDIR         21
+#define GDB_EINVAL         22
+#define GDB_ENFILE         23
+#define GDB_EMFILE         24
+#define GDB_EFBIG          27
+#define GDB_ENOSPC         28
+#define GDB_ESPIPE         29
+#define GDB_EROFS          30
+#define GDB_ENAMETOOLONG   91
+#define GDB_EUNKNOWN       9999
+
 /* For gdb file i/o stat/fstat. */
 typedef uint32_t gdb_mode_t;
 typedef uint32_t gdb_time_t;
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 15/74] semihosting: Use struct gdb_stat in common_semi_flen_cb
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (13 preceding siblings ...)
  2022-05-03 19:47 ` [PATCH v2 14/74] include/exec: Define errno values in gdbstub.h Richard Henderson
@ 2022-05-03 19:47 ` Richard Henderson
  2022-05-03 19:47 ` [PATCH v2 16/74] semihosting: Split is_64bit_semihosting per target Richard Henderson
                   ` (58 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:47 UTC (permalink / raw)
  To: qemu-devel

Use offsetof instead of an integer constant.
Load the entire 64-bit size while we're at it.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 semihosting/arm-compat-semi.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index a1fc4ea039..a6c6e5baf6 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -324,12 +324,12 @@ static target_ulong common_semi_flen_buf(CPUState *cs)
 static void
 common_semi_flen_cb(CPUState *cs, target_ulong ret, target_ulong err)
 {
-    /* The size is always stored in big-endian order, extract
-       the value. We assume the size always fit in 32 bits.  */
-    uint32_t size;
-    cpu_memory_rw_debug(cs, common_semi_flen_buf(cs) + 32,
-                        (uint8_t *)&size, 4, 0);
-    size = be32_to_cpu(size);
+    /* The size is always stored in big-endian order, extract the value. */
+    uint64_t size;
+    cpu_memory_rw_debug(cs, common_semi_flen_buf(cs) +
+                        offsetof(struct gdb_stat, gdb_st_size),
+                        &size, 8, 0);
+    size = be64_to_cpu(size);
     common_semi_cb(cs, -1, err);
     common_semi_set_ret(cs, size);
 }
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 16/74] semihosting: Split is_64bit_semihosting per target
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (14 preceding siblings ...)
  2022-05-03 19:47 ` [PATCH v2 15/74] semihosting: Use struct gdb_stat in common_semi_flen_cb Richard Henderson
@ 2022-05-03 19:47 ` Richard Henderson
  2022-05-04  8:58   ` Alistair Francis
  2022-05-03 19:47 ` [PATCH v2 17/74] semihosting: Split common_semi_flen_buf " Richard Henderson
                   ` (57 subsequent siblings)
  73 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:47 UTC (permalink / raw)
  To: qemu-devel

We already have some larger ifdef blocks for ARM and RISCV;
split the function into multiple implementations per arch.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 semihosting/arm-compat-semi.c | 19 ++++++++-----------
 1 file changed, 8 insertions(+), 11 deletions(-)

diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index a6c6e5baf6..7fc60e223a 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -213,6 +213,10 @@ common_semi_sys_exit_extended(CPUState *cs, int nr)
     return (nr == TARGET_SYS_EXIT_EXTENDED || is_a64(cs->env_ptr));
 }
 
+static inline bool is_64bit_semihosting(CPUArchState *env)
+{
+    return is_a64(env);
+}
 #endif /* TARGET_ARM */
 
 #ifdef TARGET_RISCV
@@ -238,6 +242,10 @@ common_semi_sys_exit_extended(CPUState *cs, int nr)
     return (nr == TARGET_SYS_EXIT_EXTENDED || sizeof(target_ulong) == 8);
 }
 
+static inline bool is_64bit_semihosting(CPUArchState *env)
+{
+    return riscv_cpu_mxl(env) != MXL_RV32;
+}
 #endif
 
 /*
@@ -586,17 +594,6 @@ static const GuestFDFunctions guestfd_fns[] = {
  * call if the memory read fails. Eventually we could use a generic
  * CPUState helper function here.
  */
-static inline bool is_64bit_semihosting(CPUArchState *env)
-{
-#if defined(TARGET_ARM)
-    return is_a64(env);
-#elif defined(TARGET_RISCV)
-    return riscv_cpu_mxl(env) != MXL_RV32;
-#else
-#error un-handled architecture
-#endif
-}
-
 
 #define GET_ARG(n) do {                                 \
     if (is_64bit_semihosting(env)) {                    \
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 17/74] semihosting: Split common_semi_flen_buf per target
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (15 preceding siblings ...)
  2022-05-03 19:47 ` [PATCH v2 16/74] semihosting: Split is_64bit_semihosting per target Richard Henderson
@ 2022-05-03 19:47 ` Richard Henderson
  2022-05-04  8:59   ` Alistair Francis
  2022-05-03 19:47 ` [PATCH v2 18/74] semihosting: Split out common_semi_has_synccache Richard Henderson
                   ` (56 subsequent siblings)
  73 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:47 UTC (permalink / raw)
  To: qemu-devel

We already have some larger ifdef blocks for ARM and RISCV;
split out common_semi_stack_bottom per target.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 semihosting/arm-compat-semi.c | 44 +++++++++++++++++------------------
 1 file changed, 21 insertions(+), 23 deletions(-)

diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index 7fc60e223a..b2816e9f66 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -217,6 +217,13 @@ static inline bool is_64bit_semihosting(CPUArchState *env)
 {
     return is_a64(env);
 }
+
+static inline target_ulong common_semi_stack_bottom(CPUState *cs)
+{
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
+    return is_a64(env) ? env->xregs[31] : env->regs[13];
+}
 #endif /* TARGET_ARM */
 
 #ifdef TARGET_RISCV
@@ -246,6 +253,13 @@ static inline bool is_64bit_semihosting(CPUArchState *env)
 {
     return riscv_cpu_mxl(env) != MXL_RV32;
 }
+
+static inline target_ulong common_semi_stack_bottom(CPUState *cs)
+{
+    RISCVCPU *cpu = RISCV_CPU(cs);
+    CPURISCVState *env = &cpu->env;
+    return env->gpr[xSP];
+}
 #endif
 
 /*
@@ -301,31 +315,15 @@ static void common_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
     common_semi_set_ret(cs, ret);
 }
 
+/*
+ * Return an address in target memory of 64 bytes where the remote
+ * gdb should write its stat struct. (The format of this structure
+ * is defined by GDB's remote protocol and is not target-specific.)
+ * We put this on the guest's stack just below SP.
+ */
 static target_ulong common_semi_flen_buf(CPUState *cs)
 {
-    target_ulong sp;
-#ifdef TARGET_ARM
-    /* Return an address in target memory of 64 bytes where the remote
-     * gdb should write its stat struct. (The format of this structure
-     * is defined by GDB's remote protocol and is not target-specific.)
-     * We put this on the guest's stack just below SP.
-     */
-    ARMCPU *cpu = ARM_CPU(cs);
-    CPUARMState *env = &cpu->env;
-
-    if (is_a64(env)) {
-        sp = env->xregs[31];
-    } else {
-        sp = env->regs[13];
-    }
-#endif
-#ifdef TARGET_RISCV
-    RISCVCPU *cpu = RISCV_CPU(cs);
-    CPURISCVState *env = &cpu->env;
-
-    sp = env->gpr[xSP];
-#endif
-
+    target_ulong sp = common_semi_stack_bottom(cs);
     return sp - 64;
 }
 
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 18/74] semihosting: Split out common_semi_has_synccache
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (16 preceding siblings ...)
  2022-05-03 19:47 ` [PATCH v2 17/74] semihosting: Split common_semi_flen_buf " Richard Henderson
@ 2022-05-03 19:47 ` Richard Henderson
  2022-05-04  9:01   ` Alistair Francis
  2022-05-03 19:47 ` [PATCH v2 19/74] semihosting: Use env more often in do_common_semihosting Richard Henderson
                   ` (55 subsequent siblings)
  73 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:47 UTC (permalink / raw)
  To: qemu-devel

We already have some larger ifdef blocks for ARM and RISCV;
split out a boolean test for SYS_SYNCCACHE.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 semihosting/arm-compat-semi.c | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index b2816e9f66..6149be404f 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -224,6 +224,12 @@ static inline target_ulong common_semi_stack_bottom(CPUState *cs)
     CPUARMState *env = &cpu->env;
     return is_a64(env) ? env->xregs[31] : env->regs[13];
 }
+
+static inline bool common_semi_has_synccache(CPUArchState *env)
+{
+    /* Invalid for A32/T32. */
+    return !is_a64(env);
+}
 #endif /* TARGET_ARM */
 
 #ifdef TARGET_RISCV
@@ -260,6 +266,11 @@ static inline target_ulong common_semi_stack_bottom(CPUState *cs)
     CPURISCVState *env = &cpu->env;
     return env->gpr[xSP];
 }
+
+static inline bool common_semi_has_synccache(CPUArchState *env)
+{
+    return true;
+}
 #endif
 
 /*
@@ -1103,16 +1114,11 @@ void do_common_semihosting(CPUState *cs)
          * virtual address range. This is a nop for us since we don't
          * implement caches. This is only present on A64.
          */
-#ifdef TARGET_ARM
-        if (is_a64(cs->env_ptr)) {
+        if (common_semi_has_synccache(env)) {
             common_semi_set_ret(cs, 0);
             break;
         }
-#endif
-#ifdef TARGET_RISCV
-        common_semi_set_ret(cs, 0);
-#endif
-        /* fall through -- invalid for A32/T32 */
+        /* fall through */
     default:
         fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr);
         cpu_dump_state(cs, stderr, 0);
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 19/74] semihosting: Use env more often in do_common_semihosting
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (17 preceding siblings ...)
  2022-05-03 19:47 ` [PATCH v2 18/74] semihosting: Split out common_semi_has_synccache Richard Henderson
@ 2022-05-03 19:47 ` Richard Henderson
  2022-05-03 19:47 ` [PATCH v2 20/74] semihosting: Move GET_ARG/SET_ARG earlier in the file Richard Henderson
                   ` (54 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:47 UTC (permalink / raw)
  To: qemu-devel

We've already loaded cs->env_ptr into a local variable; use it.
Since env is unconditionally used, we don't need a dummy use.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/common-semi-target.h   |  62 ++++++++++++++++++
 target/riscv/common-semi-target.h |  50 +++++++++++++++
 semihosting/arm-compat-semi.c     | 101 ++----------------------------
 3 files changed, 116 insertions(+), 97 deletions(-)
 create mode 100644 target/arm/common-semi-target.h
 create mode 100644 target/riscv/common-semi-target.h

diff --git a/target/arm/common-semi-target.h b/target/arm/common-semi-target.h
new file mode 100644
index 0000000000..c20e1cca76
--- /dev/null
+++ b/target/arm/common-semi-target.h
@@ -0,0 +1,62 @@
+/*
+ * Target-specific parts of semihosting/arm-compat-semi.c.
+ *
+ * Copyright (c) 2005, 2007 CodeSourcery.
+ * Copyright (c) 2019, 2022 Linaro
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef TARGET_ARM_COMMON_SEMI_TARGET_H
+#define TARGET_ARM_COMMON_SEMI_TARGET_H
+
+#ifndef CONFIG_USER_ONLY
+#include "hw/arm/boot.h"
+#endif
+
+static inline target_ulong common_semi_arg(CPUState *cs, int argno)
+{
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
+    if (is_a64(env)) {
+        return env->xregs[argno];
+    } else {
+        return env->regs[argno];
+    }
+}
+
+static inline void common_semi_set_ret(CPUState *cs, target_ulong ret)
+{
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
+    if (is_a64(env)) {
+        env->xregs[0] = ret;
+    } else {
+        env->regs[0] = ret;
+    }
+}
+
+static inline bool common_semi_sys_exit_extended(CPUState *cs, int nr)
+{
+    return (nr == TARGET_SYS_EXIT_EXTENDED || is_a64(cs->env_ptr));
+}
+
+static inline bool is_64bit_semihosting(CPUArchState *env)
+{
+    return is_a64(env);
+}
+
+static inline target_ulong common_semi_stack_bottom(CPUState *cs)
+{
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
+    return is_a64(env) ? env->xregs[31] : env->regs[13];
+}
+
+static inline bool common_semi_has_synccache(CPUArchState *env)
+{
+    /* Invalid for A32/T32 */
+    return !is_a64(env);
+}
+
+#endif
diff --git a/target/riscv/common-semi-target.h b/target/riscv/common-semi-target.h
new file mode 100644
index 0000000000..7c8a59e0cc
--- /dev/null
+++ b/target/riscv/common-semi-target.h
@@ -0,0 +1,50 @@
+/*
+ * Target-specific parts of semihosting/arm-compat-semi.c.
+ *
+ * Copyright (c) 2005, 2007 CodeSourcery.
+ * Copyright (c) 2019, 2022 Linaro
+ * Copyright © 2020 by Keith Packard <keithp@keithp.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef TARGET_RISCV_COMMON_SEMI_TARGET_H
+#define TARGET_RISCV_COMMON_SEMI_TARGET_H
+
+static inline target_ulong common_semi_arg(CPUState *cs, int argno)
+{
+    RISCVCPU *cpu = RISCV_CPU(cs);
+    CPURISCVState *env = &cpu->env;
+    return env->gpr[xA0 + argno];
+}
+
+static inline void common_semi_set_ret(CPUState *cs, target_ulong ret)
+{
+    RISCVCPU *cpu = RISCV_CPU(cs);
+    CPURISCVState *env = &cpu->env;
+    env->gpr[xA0] = ret;
+}
+
+static inline bool common_semi_sys_exit_extended(CPUState *cs, int nr)
+{
+    return (nr == TARGET_SYS_EXIT_EXTENDED || sizeof(target_ulong) == 8);
+}
+
+static inline bool is_64bit_semihosting(CPUArchState *env)
+{
+    return riscv_cpu_mxl(env) != MXL_RV32;
+}
+
+static inline target_ulong common_semi_stack_bottom(CPUState *cs)
+{
+    RISCVCPU *cpu = RISCV_CPU(cs);
+    CPURISCVState *env = &cpu->env;
+    return env->gpr[xSP];
+}
+
+static inline bool common_semi_has_synccache(CPUArchState *env)
+{
+    return true;
+}
+
+#endif
diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index 6149be404f..3a740482f9 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -46,9 +46,6 @@
 #else
 #include "qemu/cutils.h"
 #include "hw/loader.h"
-#ifdef TARGET_ARM
-#include "hw/arm/boot.h"
-#endif
 #include "hw/boards.h"
 #endif
 
@@ -182,96 +179,7 @@ static LayoutInfo common_semi_find_bases(CPUState *cs)
 
 #endif
 
-#ifdef TARGET_ARM
-static inline target_ulong
-common_semi_arg(CPUState *cs, int argno)
-{
-    ARMCPU *cpu = ARM_CPU(cs);
-    CPUARMState *env = &cpu->env;
-    if (is_a64(env)) {
-        return env->xregs[argno];
-    } else {
-        return env->regs[argno];
-    }
-}
-
-static inline void
-common_semi_set_ret(CPUState *cs, target_ulong ret)
-{
-    ARMCPU *cpu = ARM_CPU(cs);
-    CPUARMState *env = &cpu->env;
-    if (is_a64(env)) {
-        env->xregs[0] = ret;
-    } else {
-        env->regs[0] = ret;
-    }
-}
-
-static inline bool
-common_semi_sys_exit_extended(CPUState *cs, int nr)
-{
-    return (nr == TARGET_SYS_EXIT_EXTENDED || is_a64(cs->env_ptr));
-}
-
-static inline bool is_64bit_semihosting(CPUArchState *env)
-{
-    return is_a64(env);
-}
-
-static inline target_ulong common_semi_stack_bottom(CPUState *cs)
-{
-    ARMCPU *cpu = ARM_CPU(cs);
-    CPUARMState *env = &cpu->env;
-    return is_a64(env) ? env->xregs[31] : env->regs[13];
-}
-
-static inline bool common_semi_has_synccache(CPUArchState *env)
-{
-    /* Invalid for A32/T32. */
-    return !is_a64(env);
-}
-#endif /* TARGET_ARM */
-
-#ifdef TARGET_RISCV
-static inline target_ulong
-common_semi_arg(CPUState *cs, int argno)
-{
-    RISCVCPU *cpu = RISCV_CPU(cs);
-    CPURISCVState *env = &cpu->env;
-    return env->gpr[xA0 + argno];
-}
-
-static inline void
-common_semi_set_ret(CPUState *cs, target_ulong ret)
-{
-    RISCVCPU *cpu = RISCV_CPU(cs);
-    CPURISCVState *env = &cpu->env;
-    env->gpr[xA0] = ret;
-}
-
-static inline bool
-common_semi_sys_exit_extended(CPUState *cs, int nr)
-{
-    return (nr == TARGET_SYS_EXIT_EXTENDED || sizeof(target_ulong) == 8);
-}
-
-static inline bool is_64bit_semihosting(CPUArchState *env)
-{
-    return riscv_cpu_mxl(env) != MXL_RV32;
-}
-
-static inline target_ulong common_semi_stack_bottom(CPUState *cs)
-{
-    RISCVCPU *cpu = RISCV_CPU(cs);
-    CPURISCVState *env = &cpu->env;
-    return env->gpr[xSP];
-}
-
-static inline bool common_semi_has_synccache(CPUArchState *env)
-{
-    return true;
-}
-#endif
+#include "common-semi-target.h"
 
 /*
  * The semihosting API has no concept of its errno being thread-safe,
@@ -646,7 +554,6 @@ void do_common_semihosting(CPUState *cs)
     GuestFD *gf;
     int64_t elapsed;
 
-    (void) env; /* Used implicitly by arm lock_user macro */
     nr = common_semi_arg(cs, 0) & 0xffffffffU;
     args = common_semi_arg(cs, 1);
 
@@ -729,12 +636,12 @@ void do_common_semihosting(CPUState *cs)
         break;
 
     case TARGET_SYS_WRITEC:
-        qemu_semihosting_console_outc(cs->env_ptr, args);
+        qemu_semihosting_console_outc(env, args);
         common_semi_set_ret(cs, 0xdeadbeef);
         break;
 
     case TARGET_SYS_WRITE0:
-        ret = qemu_semihosting_console_outs(cs->env_ptr, args);
+        ret = qemu_semihosting_console_outs(env, args);
         common_semi_set_ret(cs, ret);
         break;
 
@@ -765,7 +672,7 @@ void do_common_semihosting(CPUState *cs)
         break;
 
     case TARGET_SYS_READC:
-        ret = qemu_semihosting_console_inc(cs->env_ptr);
+        ret = qemu_semihosting_console_inc(env);
         common_semi_set_ret(cs, ret);
         break;
 
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 20/74] semihosting: Move GET_ARG/SET_ARG earlier in the file
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (18 preceding siblings ...)
  2022-05-03 19:47 ` [PATCH v2 19/74] semihosting: Use env more often in do_common_semihosting Richard Henderson
@ 2022-05-03 19:47 ` Richard Henderson
  2022-05-03 19:47 ` [PATCH v2 21/74] semihosting: Split out semihost_sys_open Richard Henderson
                   ` (53 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:47 UTC (permalink / raw)
  To: qemu-devel

Moving this to be useful for another function
besides do_common_semihosting.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 semihosting/arm-compat-semi.c | 52 +++++++++++++++++------------------
 1 file changed, 26 insertions(+), 26 deletions(-)

diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index 3a740482f9..49f976cbc5 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -181,6 +181,32 @@ static LayoutInfo common_semi_find_bases(CPUState *cs)
 
 #include "common-semi-target.h"
 
+/*
+ * Read the input value from the argument block; fail the semihosting
+ * call if the memory read fails. Eventually we could use a generic
+ * CPUState helper function here.
+ */
+
+#define GET_ARG(n) do {                                 \
+    if (is_64bit_semihosting(env)) {                    \
+        if (get_user_u64(arg ## n, args + (n) * 8)) {   \
+            common_semi_cb(cs, -1, EFAULT);             \
+            return;                                     \
+        }                                               \
+    } else {                                            \
+        if (get_user_u32(arg ## n, args + (n) * 4)) {   \
+            common_semi_cb(cs, -1, EFAULT);             \
+            return;                                     \
+        }                                               \
+    }                                                   \
+} while (0)
+
+#define SET_ARG(n, val)                                 \
+    (is_64bit_semihosting(env) ?                        \
+     put_user_u64(val, args + (n) * 8) :                \
+     put_user_u32(val, args + (n) * 4))
+
+
 /*
  * The semihosting API has no concept of its errno being thread-safe,
  * as the API design predates SMP CPUs and was intended as a simple
@@ -506,32 +532,6 @@ static const GuestFDFunctions guestfd_fns[] = {
     },
 };
 
-/*
- * Read the input value from the argument block; fail the semihosting
- * call if the memory read fails. Eventually we could use a generic
- * CPUState helper function here.
- */
-
-#define GET_ARG(n) do {                                 \
-    if (is_64bit_semihosting(env)) {                    \
-        if (get_user_u64(arg ## n, args + (n) * 8)) {   \
-            common_semi_cb(cs, -1, EFAULT);             \
-            return;                                     \
-        }                                               \
-    } else {                                            \
-        if (get_user_u32(arg ## n, args + (n) * 4)) {   \
-            common_semi_cb(cs, -1, EFAULT);             \
-            return;                                     \
-        }                                               \
-    }                                                   \
-} while (0)
-
-#define SET_ARG(n, val)                                 \
-    (is_64bit_semihosting(env) ?                        \
-     put_user_u64(val, args + (n) * 8) :                \
-     put_user_u32(val, args + (n) * 4))
-
-
 /*
  * Do a semihosting call.
  *
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 21/74] semihosting: Split out semihost_sys_open
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (19 preceding siblings ...)
  2022-05-03 19:47 ` [PATCH v2 20/74] semihosting: Move GET_ARG/SET_ARG earlier in the file Richard Henderson
@ 2022-05-03 19:47 ` Richard Henderson
  2022-05-03 19:47 ` [PATCH v2 22/74] semihosting: Split out semihost_sys_close Richard Henderson
                   ` (52 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:47 UTC (permalink / raw)
  To: qemu-devel

Split out the non-ARM specific portions of SYS_OPEN to a
reusable function.  This handles gdb and host file i/o.

Add helpers to validate the length of the filename string.
Prepare for usage by other semihosting by allowing the
filename length parameter to be 0, and calling strlen.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/semihosting/syscalls.h |  25 +++++
 semihosting/arm-compat-semi.c  |  50 +--------
 semihosting/guestfd.c          |   5 +
 semihosting/syscalls.c         | 186 +++++++++++++++++++++++++++++++++
 semihosting/meson.build        |   1 +
 5 files changed, 222 insertions(+), 45 deletions(-)
 create mode 100644 include/semihosting/syscalls.h
 create mode 100644 semihosting/syscalls.c

diff --git a/include/semihosting/syscalls.h b/include/semihosting/syscalls.h
new file mode 100644
index 0000000000..991658bf79
--- /dev/null
+++ b/include/semihosting/syscalls.h
@@ -0,0 +1,25 @@
+/*
+ * Syscall implementations for semihosting.
+ *
+ * Copyright (c) 2022 Linaro
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef SEMIHOSTING_SYSCALLS_H
+#define SEMIHOSTING_SYSCALLS_H
+
+/*
+ * Argument loading from the guest is performed by the caller;
+ * results are returned via the 'complete' callback.
+ *
+ * String operands are in address/len pairs.  The len argument may be 0
+ * (when the semihosting abi does not already provide the length),
+ * or non-zero (where it should include the terminating zero).
+ */
+
+void semihost_sys_open(CPUState *cs, gdb_syscall_complete_cb complete,
+                       target_ulong fname, target_ulong fname_len,
+                       int gdb_flags, int mode);
+
+#endif /* SEMIHOSTING_SYSCALLS_H */
diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index 49f976cbc5..4a2f0c9202 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -35,9 +35,10 @@
 #include "semihosting/semihost.h"
 #include "semihosting/console.h"
 #include "semihosting/common-semi.h"
-#include "semihosting/guestfd.h"
 #include "qemu/timer.h"
 #include "exec/gdbstub.h"
+#include "semihosting/guestfd.h"
+#include "semihosting/syscalls.h"
 
 #ifdef CONFIG_USER_ONLY
 #include "qemu.h"
@@ -98,21 +99,6 @@ static int gdb_open_modeflags[12] = {
     GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY
 };
 
-static int open_modeflags[12] = {
-    O_RDONLY,
-    O_RDONLY | O_BINARY,
-    O_RDWR,
-    O_RDWR | O_BINARY,
-    O_WRONLY | O_CREAT | O_TRUNC,
-    O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
-    O_RDWR | O_CREAT | O_TRUNC,
-    O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
-    O_WRONLY | O_CREAT | O_APPEND,
-    O_WRONLY | O_CREAT | O_APPEND | O_BINARY,
-    O_RDWR | O_CREAT | O_APPEND,
-    O_RDWR | O_CREAT | O_APPEND | O_BINARY
-};
-
 #ifndef CONFIG_USER_ONLY
 
 /**
@@ -285,20 +271,6 @@ common_semi_flen_cb(CPUState *cs, target_ulong ret, target_ulong err)
     common_semi_set_ret(cs, size);
 }
 
-static int common_semi_open_guestfd;
-
-static void
-common_semi_open_cb(CPUState *cs, target_ulong ret, target_ulong err)
-{
-    if (ret == (target_ulong)-1) {
-        dealloc_guestfd(common_semi_open_guestfd);
-    } else {
-        associate_guestfd(common_semi_open_guestfd, ret);
-        ret = common_semi_open_guestfd;
-    }
-    common_semi_cb(cs, ret, err);
-}
-
 /*
  * Types for functions implementing various semihosting calls
  * for specific types of guest file descriptor. These must all
@@ -602,22 +574,10 @@ void do_common_semihosting(CPUState *cs)
                 staticfile_guestfd(ret, featurefile_data,
                                    sizeof(featurefile_data));
             }
-        } else if (use_gdb_syscalls()) {
-            unlock_user(s, arg0, 0);
-            common_semi_open_guestfd = alloc_guestfd();
-            gdb_do_syscall(common_semi_open_cb,
-                           "open,%s,%x,1a4", arg0, (int)arg2 + 1,
-                           gdb_open_modeflags[arg1]);
-            break;
         } else {
-            hostfd = open(s, open_modeflags[arg1], 0644);
-            if (hostfd < 0) {
-                ret = -1;
-                err = errno;
-            } else {
-                ret = alloc_guestfd();
-                associate_guestfd(ret, hostfd);
-            }
+            semihost_sys_open(cs, common_semi_cb, arg0, arg2 + 1,
+                              gdb_open_modeflags[arg1], 0644);
+            break;
         }
         unlock_user(s, arg0, 0);
         common_semi_cb(cs, ret, err);
diff --git a/semihosting/guestfd.c b/semihosting/guestfd.c
index b6405f5663..7ac2e147a8 100644
--- a/semihosting/guestfd.c
+++ b/semihosting/guestfd.c
@@ -11,6 +11,11 @@
 #include "qemu/osdep.h"
 #include "exec/gdbstub.h"
 #include "semihosting/guestfd.h"
+#ifdef CONFIG_USER_ONLY
+#include "qemu.h"
+#else
+#include "semihosting/softmmu-uaccess.h"
+#endif
 
 static GArray *guestfd_array;
 
diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c
new file mode 100644
index 0000000000..a44d5cbae2
--- /dev/null
+++ b/semihosting/syscalls.c
@@ -0,0 +1,186 @@
+/*
+ * Syscall implementations for semihosting.
+ *
+ * Copyright (c) 2022 Linaro
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "exec/gdbstub.h"
+#include "semihosting/guestfd.h"
+#include "semihosting/syscalls.h"
+#ifdef CONFIG_USER_ONLY
+#include "qemu.h"
+#else
+#include "semihosting/softmmu-uaccess.h"
+#endif
+
+
+/*
+ * Validate or compute the length of the string (including terminator).
+ */
+static int validate_strlen(CPUState *cs, target_ulong str, target_ulong tlen)
+{
+    CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
+    char c;
+
+    if (tlen == 0) {
+        ssize_t slen = target_strlen(str);
+
+        if (slen < 0) {
+            return -GDB_EFAULT;
+        }
+        if (slen >= INT32_MAX) {
+            return -GDB_ENAMETOOLONG;
+        }
+        return slen + 1;
+    }
+    if (tlen > INT32_MAX) {
+        return -GDB_ENAMETOOLONG;
+    }
+    if (get_user_u8(c, str + tlen - 1)) {
+        return -GDB_EFAULT;
+    }
+    if (c != 0) {
+        return -GDB_EINVAL;
+    }
+    return tlen;
+}
+
+static int validate_lock_user_string(char **pstr, CPUState *cs,
+                                     target_ulong tstr, target_ulong tlen)
+{
+    int ret = validate_strlen(cs, tstr, tlen);
+    CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
+    char *str = NULL;
+
+    if (ret > 0) {
+        str = lock_user(VERIFY_READ, tstr, ret, true);
+        ret = str ? 0 : -GDB_EFAULT;
+    }
+    *pstr = str;
+    return ret;
+}
+
+static int errno_for_gdb(void)
+{
+#define E(N)  case E##N: return GDB_E##N
+
+    switch (errno) {
+    E(PERM);
+    E(NOENT);
+    E(INTR);
+    E(BADF);
+    E(ACCES);
+    E(FAULT);
+    E(BUSY);
+    E(EXIST);
+    E(NODEV);
+    E(NOTDIR);
+    E(ISDIR);
+    E(INVAL);
+    E(NFILE);
+    E(MFILE);
+    E(FBIG);
+    E(NOSPC);
+    E(SPIPE);
+    E(ROFS);
+    E(NAMETOOLONG);
+    }
+    return GDB_EUNKNOWN;
+
+#undef E
+}
+
+/*
+ * GDB semihosting syscall implementations.
+ */
+
+static gdb_syscall_complete_cb gdb_open_complete;
+
+static void gdb_open_cb(CPUState *cs, target_ulong ret, target_ulong err)
+{
+    if (!err) {
+        int guestfd = alloc_guestfd();
+        associate_guestfd(guestfd, ret);
+        ret = guestfd;
+    }
+    gdb_open_complete(cs, ret, err);
+}
+
+static void gdb_open(CPUState *cs, gdb_syscall_complete_cb complete,
+                     target_ulong fname, target_ulong fname_len,
+                     int gdb_flags, int mode)
+{
+    int len = validate_strlen(cs, fname, fname_len);
+    if (len < 0) {
+        complete(cs, -1, -len);
+        return;
+    }
+
+    gdb_open_complete = complete;
+    gdb_do_syscall(gdb_open_cb, "open,%s,%x,%x",
+                   fname, len, (target_ulong)gdb_flags, (target_ulong)mode);
+}
+
+/*
+ * Host semihosting syscall implementations.
+ */
+
+static void host_open(CPUState *cs, gdb_syscall_complete_cb complete,
+                      target_ulong fname, target_ulong fname_len,
+                      int gdb_flags, int mode)
+{
+    CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
+    char *p;
+    int ret, host_flags;
+
+    ret = validate_lock_user_string(&p, cs, fname, fname_len);
+    if (ret < 0) {
+        complete(cs, -1, -ret);
+        return;
+    }
+
+    if (gdb_flags & GDB_O_WRONLY) {
+        host_flags = O_WRONLY;
+    } else if (gdb_flags & GDB_O_RDWR) {
+        host_flags = O_RDWR;
+    } else {
+        host_flags = O_RDONLY;
+    }
+    if (gdb_flags & GDB_O_CREAT) {
+        host_flags |= O_CREAT;
+    }
+    if (gdb_flags & GDB_O_TRUNC) {
+        host_flags |= O_TRUNC;
+    }
+    if (gdb_flags & GDB_O_EXCL) {
+        host_flags |= O_EXCL;
+    }
+
+    ret = open(p, host_flags, mode);
+    if (ret < 0) {
+        complete(cs, -1, errno_for_gdb());
+    } else {
+        int guestfd = alloc_guestfd();
+        associate_guestfd(guestfd, ret);
+        complete(cs, guestfd, 0);
+    }
+    unlock_user(p, fname, 0);
+}
+
+/*
+ * Syscall entry points.
+ */
+
+void semihost_sys_open(CPUState *cs, gdb_syscall_complete_cb complete,
+                       target_ulong fname, target_ulong fname_len,
+                       int gdb_flags, int mode)
+{
+    if (use_gdb_syscalls()) {
+        gdb_open(cs, complete, fname, fname_len, gdb_flags, mode);
+    } else {
+        host_open(cs, complete, fname, fname_len, gdb_flags, mode);
+    }
+}
diff --git a/semihosting/meson.build b/semihosting/meson.build
index d2c1c37bfd..8057db5494 100644
--- a/semihosting/meson.build
+++ b/semihosting/meson.build
@@ -1,5 +1,6 @@
 specific_ss.add(when: 'CONFIG_SEMIHOSTING', if_true: files(
   'guestfd.c',
+  'syscalls.c',
 ))
 
 specific_ss.add(when: ['CONFIG_SEMIHOSTING', 'CONFIG_SOFTMMU'], if_true: files(
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 22/74] semihosting: Split out semihost_sys_close
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (20 preceding siblings ...)
  2022-05-03 19:47 ` [PATCH v2 21/74] semihosting: Split out semihost_sys_open Richard Henderson
@ 2022-05-03 19:47 ` Richard Henderson
  2022-05-03 19:47 ` [PATCH v2 23/74] semihosting: Split out semihost_sys_read Richard Henderson
                   ` (51 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:47 UTC (permalink / raw)
  To: qemu-devel

Split out the non-ARM specific portions of SYS_CLOSE to a
reusable function.  This handles all GuestFD.

Note that gdb_do_syscall %x reads target_ulong, not int.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/semihosting/syscalls.h |  3 +++
 semihosting/arm-compat-semi.c  | 41 +----------------------------
 semihosting/guestfd.c          |  7 ++++-
 semihosting/syscalls.c         | 47 ++++++++++++++++++++++++++++++++++
 4 files changed, 57 insertions(+), 41 deletions(-)

diff --git a/include/semihosting/syscalls.h b/include/semihosting/syscalls.h
index 991658bf79..00e718f11d 100644
--- a/include/semihosting/syscalls.h
+++ b/include/semihosting/syscalls.h
@@ -22,4 +22,7 @@ void semihost_sys_open(CPUState *cs, gdb_syscall_complete_cb complete,
                        target_ulong fname, target_ulong fname_len,
                        int gdb_flags, int mode);
 
+void semihost_sys_close(CPUState *cs, gdb_syscall_complete_cb complete,
+                        int fd);
+
 #endif /* SEMIHOSTING_SYSCALLS_H */
diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index 4a2f0c9202..8ebe3aad55 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -277,7 +277,6 @@ common_semi_flen_cb(CPUState *cs, target_ulong ret, target_ulong err)
  * do the work and return the required return value to the guest
  * via common_semi_cb.
  */
-typedef void sys_closefn(CPUState *cs, GuestFD *gf);
 typedef void sys_writefn(CPUState *cs, GuestFD *gf,
                          target_ulong buf, uint32_t len);
 typedef void sys_readfn(CPUState *cs, GuestFD *gf,
@@ -286,23 +285,6 @@ typedef void sys_isattyfn(CPUState *cs, GuestFD *gf);
 typedef void sys_seekfn(CPUState *cs, GuestFD *gf, target_ulong offset);
 typedef void sys_flenfn(CPUState *cs, GuestFD *gf);
 
-static void host_closefn(CPUState *cs, GuestFD *gf)
-{
-    int ret;
-    /*
-     * Only close the underlying host fd if it's one we opened on behalf
-     * of the guest in SYS_OPEN.
-     */
-    if (gf->hostfd == STDIN_FILENO ||
-        gf->hostfd == STDOUT_FILENO ||
-        gf->hostfd == STDERR_FILENO) {
-        ret = 0;
-    } else {
-        ret = close(gf->hostfd);
-    }
-    common_semi_cb(cs, ret, ret ? errno : 0);
-}
-
 static void host_writefn(CPUState *cs, GuestFD *gf,
                          target_ulong buf, uint32_t len)
 {
@@ -363,11 +345,6 @@ static void host_flenfn(CPUState *cs, GuestFD *gf)
     }
 }
 
-static void gdb_closefn(CPUState *cs, GuestFD *gf)
-{
-    gdb_do_syscall(common_semi_cb, "close,%x", gf->hostfd);
-}
-
 static void gdb_writefn(CPUState *cs, GuestFD *gf,
                         target_ulong buf, uint32_t len)
 {
@@ -415,12 +392,6 @@ static const uint8_t featurefile_data[] = {
     SH_EXT_EXIT_EXTENDED | SH_EXT_STDOUT_STDERR, /* Feature byte 0 */
 };
 
-static void staticfile_closefn(CPUState *cs, GuestFD *gf)
-{
-    /* Nothing to do */
-    common_semi_cb(cs, 0, 0);
-}
-
 static void staticfile_writefn(CPUState *cs, GuestFD *gf,
                                target_ulong buf, uint32_t len)
 {
@@ -469,7 +440,6 @@ static void staticfile_flenfn(CPUState *cs, GuestFD *gf)
 }
 
 typedef struct GuestFDFunctions {
-    sys_closefn *closefn;
     sys_writefn *writefn;
     sys_readfn *readfn;
     sys_isattyfn *isattyfn;
@@ -479,7 +449,6 @@ typedef struct GuestFDFunctions {
 
 static const GuestFDFunctions guestfd_fns[] = {
     [GuestFDHost] = {
-        .closefn = host_closefn,
         .writefn = host_writefn,
         .readfn = host_readfn,
         .isattyfn = host_isattyfn,
@@ -487,7 +456,6 @@ static const GuestFDFunctions guestfd_fns[] = {
         .flenfn = host_flenfn,
     },
     [GuestFDGDB] = {
-        .closefn = gdb_closefn,
         .writefn = gdb_writefn,
         .readfn = gdb_readfn,
         .isattyfn = gdb_isattyfn,
@@ -495,7 +463,6 @@ static const GuestFDFunctions guestfd_fns[] = {
         .flenfn = gdb_flenfn,
     },
     [GuestFDStatic] = {
-        .closefn = staticfile_closefn,
         .writefn = staticfile_writefn,
         .readfn = staticfile_readfn,
         .isattyfn = staticfile_isattyfn,
@@ -586,13 +553,7 @@ void do_common_semihosting(CPUState *cs)
 
     case TARGET_SYS_CLOSE:
         GET_ARG(0);
-
-        gf = get_guestfd(arg0);
-        if (!gf) {
-            goto do_badf;
-        }
-        guestfd_fns[gf->type].closefn(cs, gf);
-        dealloc_guestfd(arg0);
+        semihost_sys_close(cs, common_semi_cb, arg0);
         break;
 
     case TARGET_SYS_WRITEC:
diff --git a/semihosting/guestfd.c b/semihosting/guestfd.c
index 7ac2e147a8..e3122ebba9 100644
--- a/semihosting/guestfd.c
+++ b/semihosting/guestfd.c
@@ -49,6 +49,11 @@ int alloc_guestfd(void)
     return i;
 }
 
+static void do_dealloc_guestfd(GuestFD *gf)
+{
+    gf->type = GuestFDUnused;
+}
+
 /*
  * Look up the guestfd in the data structure; return NULL
  * for out of bounds, but don't check whether the slot is unused.
@@ -119,5 +124,5 @@ void dealloc_guestfd(int guestfd)
     GuestFD *gf = do_get_guestfd(guestfd);
 
     assert(gf);
-    gf->type = GuestFDUnused;
+    do_dealloc_guestfd(gf);
 }
diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c
index a44d5cbae2..9c4b635317 100644
--- a/semihosting/syscalls.c
+++ b/semihosting/syscalls.c
@@ -124,6 +124,12 @@ static void gdb_open(CPUState *cs, gdb_syscall_complete_cb complete,
                    fname, len, (target_ulong)gdb_flags, (target_ulong)mode);
 }
 
+static void gdb_close(CPUState *cs, gdb_syscall_complete_cb complete,
+                      GuestFD *gf)
+{
+    gdb_do_syscall(complete, "close,%x", (target_ulong)gf->hostfd);
+}
+
 /*
  * Host semihosting syscall implementations.
  */
@@ -170,6 +176,23 @@ static void host_open(CPUState *cs, gdb_syscall_complete_cb complete,
     unlock_user(p, fname, 0);
 }
 
+static void host_close(CPUState *cs, gdb_syscall_complete_cb complete,
+                       GuestFD *gf)
+{
+    /*
+     * Only close the underlying host fd if it's one we opened on behalf
+     * of the guest in SYS_OPEN.
+     */
+    if (gf->hostfd != STDIN_FILENO &&
+        gf->hostfd != STDOUT_FILENO &&
+        gf->hostfd != STDERR_FILENO &&
+        close(gf->hostfd) < 0) {
+        complete(cs, -1, errno_for_gdb());
+    } else {
+        complete(cs, 0, 0);
+    }
+}
+
 /*
  * Syscall entry points.
  */
@@ -184,3 +207,27 @@ void semihost_sys_open(CPUState *cs, gdb_syscall_complete_cb complete,
         host_open(cs, complete, fname, fname_len, gdb_flags, mode);
     }
 }
+
+void semihost_sys_close(CPUState *cs, gdb_syscall_complete_cb complete, int fd)
+{
+    GuestFD *gf = get_guestfd(fd);
+
+    if (!gf) {
+        complete(cs, -1, GDB_EBADF);
+        return;
+    }
+    switch (gf->type) {
+    case GuestFDGDB:
+        gdb_close(cs, complete, gf);
+        break;
+    case GuestFDHost:
+        host_close(cs, complete, gf);
+        break;
+    case GuestFDStatic:
+        complete(cs, 0, 0);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+    dealloc_guestfd(fd);
+}
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 23/74] semihosting: Split out semihost_sys_read
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (21 preceding siblings ...)
  2022-05-03 19:47 ` [PATCH v2 22/74] semihosting: Split out semihost_sys_close Richard Henderson
@ 2022-05-03 19:47 ` Richard Henderson
  2022-05-03 19:47 ` [PATCH v2 24/74] semihosting: Split out semihost_sys_write Richard Henderson
                   ` (50 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:47 UTC (permalink / raw)
  To: qemu-devel

Split out the non-ARM specific portions of SYS_READ to a
reusable function.  This handles all GuestFD.  Isolate the
curious ARM-specific return value processing to a new
callback, common_semi_rw_cb.

Note that gdb_do_syscall %x reads target_ulong, not int.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/semihosting/syscalls.h |  8 ++++
 semihosting/arm-compat-semi.c  | 84 ++++++++-------------------------
 semihosting/syscalls.c         | 85 ++++++++++++++++++++++++++++++++++
 3 files changed, 112 insertions(+), 65 deletions(-)

diff --git a/include/semihosting/syscalls.h b/include/semihosting/syscalls.h
index 00e718f11d..20da8138b0 100644
--- a/include/semihosting/syscalls.h
+++ b/include/semihosting/syscalls.h
@@ -18,6 +18,8 @@
  * or non-zero (where it should include the terminating zero).
  */
 
+typedef struct GuestFD GuestFD;
+
 void semihost_sys_open(CPUState *cs, gdb_syscall_complete_cb complete,
                        target_ulong fname, target_ulong fname_len,
                        int gdb_flags, int mode);
@@ -25,4 +27,10 @@ void semihost_sys_open(CPUState *cs, gdb_syscall_complete_cb complete,
 void semihost_sys_close(CPUState *cs, gdb_syscall_complete_cb complete,
                         int fd);
 
+void semihost_sys_read(CPUState *cs, gdb_syscall_complete_cb complete,
+                       int fd, target_ulong buf, target_ulong len);
+
+void semihost_sys_read_gf(CPUState *cs, gdb_syscall_complete_cb complete,
+                          GuestFD *gf, target_ulong buf, target_ulong len);
+
 #endif /* SEMIHOSTING_SYSCALLS_H */
diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index 8ebe3aad55..7b6df09f35 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -233,7 +233,6 @@ static void common_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
         target_ulong reg0 = common_semi_arg(cs, 0);
         switch (reg0) {
         case TARGET_SYS_WRITE:
-        case TARGET_SYS_READ:
             ret = common_semi_syscall_len - ret;
             break;
         case TARGET_SYS_SEEK:
@@ -246,6 +245,24 @@ static void common_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
     common_semi_set_ret(cs, ret);
 }
 
+/*
+ * SYS_READ and SYS_WRITE always return the number of bytes not read/written.
+ * There is no error condition, other than returning the original length.
+ */
+static void common_semi_rw_cb(CPUState *cs, target_ulong ret, target_ulong err)
+{
+    /* Recover the original length from the third argument. */
+    CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
+    target_ulong args = common_semi_arg(cs, 1);
+    target_ulong arg2;
+    GET_ARG(2);
+
+    if (err) {
+        ret = 0; /* error: no bytes transmitted */
+    }
+    common_semi_set_ret(cs, arg2 - ret);
+}
+
 /*
  * Return an address in target memory of 64 bytes where the remote
  * gdb should write its stat struct. (The format of this structure
@@ -279,8 +296,6 @@ common_semi_flen_cb(CPUState *cs, target_ulong ret, target_ulong err)
  */
 typedef void sys_writefn(CPUState *cs, GuestFD *gf,
                          target_ulong buf, uint32_t len);
-typedef void sys_readfn(CPUState *cs, GuestFD *gf,
-                        target_ulong buf, uint32_t len);
 typedef void sys_isattyfn(CPUState *cs, GuestFD *gf);
 typedef void sys_seekfn(CPUState *cs, GuestFD *gf, target_ulong offset);
 typedef void sys_flenfn(CPUState *cs, GuestFD *gf);
@@ -303,26 +318,6 @@ static void host_writefn(CPUState *cs, GuestFD *gf,
     common_semi_cb(cs, len - ret, 0);
 }
 
-static void host_readfn(CPUState *cs, GuestFD *gf,
-                        target_ulong buf, uint32_t len)
-{
-    CPUArchState *env = cs->env_ptr;
-    uint32_t ret = 0;
-    char *s = lock_user(VERIFY_WRITE, buf, len, 0);
-    (void) env; /* Used in arm softmmu lock_user implicitly */
-    if (s) {
-        do {
-            ret = read(gf->hostfd, s, len);
-        } while (ret == -1 && errno == EINTR);
-        unlock_user(s, buf, len);
-        if (ret == (uint32_t)-1) {
-            ret = 0;
-        }
-    }
-    /* Return bytes not read, on error as well. */
-    common_semi_cb(cs, len - ret, 0);
-}
-
 static void host_isattyfn(CPUState *cs, GuestFD *gf)
 {
     common_semi_cb(cs, isatty(gf->hostfd), 0);
@@ -352,13 +347,6 @@ static void gdb_writefn(CPUState *cs, GuestFD *gf,
     gdb_do_syscall(common_semi_cb, "write,%x,%x,%x", gf->hostfd, buf, len);
 }
 
-static void gdb_readfn(CPUState *cs, GuestFD *gf,
-                       target_ulong buf, uint32_t len)
-{
-    common_semi_syscall_len = len;
-    gdb_do_syscall(common_semi_cb, "read,%x,%x,%x", gf->hostfd, buf, len);
-}
-
 static void gdb_isattyfn(CPUState *cs, GuestFD *gf)
 {
     gdb_do_syscall(common_semi_cb, "isatty,%x", gf->hostfd);
@@ -399,30 +387,6 @@ static void staticfile_writefn(CPUState *cs, GuestFD *gf,
     common_semi_cb(cs, -1, EBADF);
 }
 
-static void staticfile_readfn(CPUState *cs, GuestFD *gf,
-                              target_ulong buf, uint32_t len)
-{
-    CPUArchState *env = cs->env_ptr;
-    uint32_t i = 0;
-    char *s;
-
-    (void) env; /* Used in arm softmmu lock_user implicitly */
-    s = lock_user(VERIFY_WRITE, buf, len, 0);
-    if (s) {
-        for (i = 0; i < len; i++) {
-            if (gf->staticfile.off >= gf->staticfile.len) {
-                break;
-            }
-            s[i] = gf->staticfile.data[gf->staticfile.off];
-            gf->staticfile.off++;
-        }
-        unlock_user(s, buf, len);
-    }
-
-    /* Return number of bytes not read */
-    common_semi_cb(cs, len - i, 0);
-}
-
 static void staticfile_isattyfn(CPUState *cs, GuestFD *gf)
 {
     common_semi_cb(cs, 0, 0);
@@ -441,7 +405,6 @@ static void staticfile_flenfn(CPUState *cs, GuestFD *gf)
 
 typedef struct GuestFDFunctions {
     sys_writefn *writefn;
-    sys_readfn *readfn;
     sys_isattyfn *isattyfn;
     sys_seekfn *seekfn;
     sys_flenfn *flenfn;
@@ -450,21 +413,18 @@ typedef struct GuestFDFunctions {
 static const GuestFDFunctions guestfd_fns[] = {
     [GuestFDHost] = {
         .writefn = host_writefn,
-        .readfn = host_readfn,
         .isattyfn = host_isattyfn,
         .seekfn = host_seekfn,
         .flenfn = host_flenfn,
     },
     [GuestFDGDB] = {
         .writefn = gdb_writefn,
-        .readfn = gdb_readfn,
         .isattyfn = gdb_isattyfn,
         .seekfn = gdb_seekfn,
         .flenfn = gdb_flenfn,
     },
     [GuestFDStatic] = {
         .writefn = staticfile_writefn,
-        .readfn = staticfile_readfn,
         .isattyfn = staticfile_isattyfn,
         .seekfn = staticfile_seekfn,
         .flenfn = staticfile_flenfn,
@@ -583,13 +543,7 @@ void do_common_semihosting(CPUState *cs)
         GET_ARG(0);
         GET_ARG(1);
         GET_ARG(2);
-        len = arg2;
-
-        gf = get_guestfd(arg0);
-        if (!gf) {
-            goto do_badf;
-        }
-        guestfd_fns[gf->type].readfn(cs, gf, arg1, len);
+        semihost_sys_read(cs, common_semi_rw_cb, arg0, arg1, arg2);
         break;
 
     case TARGET_SYS_READC:
diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c
index 9c4b635317..7c18f77898 100644
--- a/semihosting/syscalls.c
+++ b/semihosting/syscalls.c
@@ -130,6 +130,13 @@ static void gdb_close(CPUState *cs, gdb_syscall_complete_cb complete,
     gdb_do_syscall(complete, "close,%x", (target_ulong)gf->hostfd);
 }
 
+static void gdb_read(CPUState *cs, gdb_syscall_complete_cb complete,
+                     GuestFD *gf, target_ulong buf, target_ulong len)
+{
+    gdb_do_syscall(complete, "read,%x,%x,%x",
+                   (target_ulong)gf->hostfd, buf, len);
+}
+
 /*
  * Host semihosting syscall implementations.
  */
@@ -193,6 +200,54 @@ static void host_close(CPUState *cs, gdb_syscall_complete_cb complete,
     }
 }
 
+static void host_read(CPUState *cs, gdb_syscall_complete_cb complete,
+                      GuestFD *gf, target_ulong buf, target_ulong len)
+{
+    CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
+    void *ptr = lock_user(VERIFY_WRITE, buf, len, 0);
+    ssize_t ret;
+
+    if (!ptr) {
+        complete(cs, -1, GDB_EFAULT);
+        return;
+    }
+    do {
+        ret = read(gf->hostfd, ptr, len);
+    } while (ret == -1 && errno == EINTR);
+    if (ret == -1) {
+        complete(cs, -1, errno_for_gdb());
+        unlock_user(ptr, buf, 0);
+    } else {
+        complete(cs, ret, 0);
+        unlock_user(ptr, buf, ret);
+    }
+}
+
+/*
+ * Static file semihosting syscall implementations.
+ */
+
+static void staticfile_read(CPUState *cs, gdb_syscall_complete_cb complete,
+                            GuestFD *gf, target_ulong buf, target_ulong len)
+{
+    CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
+    target_ulong rest = gf->staticfile.len - gf->staticfile.off;
+    void *ptr;
+
+    if (len > rest) {
+        len = rest;
+    }
+    ptr = lock_user(VERIFY_WRITE, buf, len, 0);
+    if (!ptr) {
+        complete(cs, -1, GDB_EFAULT);
+        return;
+    }
+    memcpy(ptr, gf->staticfile.data + gf->staticfile.off, len);
+    gf->staticfile.off += len;
+    complete(cs, len, 0);
+    unlock_user(ptr, buf, len);
+}
+
 /*
  * Syscall entry points.
  */
@@ -231,3 +286,33 @@ void semihost_sys_close(CPUState *cs, gdb_syscall_complete_cb complete, int fd)
     }
     dealloc_guestfd(fd);
 }
+
+void semihost_sys_read_gf(CPUState *cs, gdb_syscall_complete_cb complete,
+                          GuestFD *gf, target_ulong buf, target_ulong len)
+{
+    switch (gf->type) {
+    case GuestFDGDB:
+        gdb_read(cs, complete, gf, buf, len);
+        break;
+    case GuestFDHost:
+        host_read(cs, complete, gf, buf, len);
+        break;
+    case GuestFDStatic:
+        staticfile_read(cs, complete, gf, buf, len);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+}
+
+void semihost_sys_read(CPUState *cs, gdb_syscall_complete_cb complete,
+                       int fd, target_ulong buf, target_ulong len)
+{
+    GuestFD *gf = get_guestfd(fd);
+
+    if (gf) {
+        semihost_sys_read_gf(cs, complete, gf, buf, len);
+    } else {
+        complete(cs, -1, GDB_EBADF);
+    }
+}
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 24/74] semihosting: Split out semihost_sys_write
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (22 preceding siblings ...)
  2022-05-03 19:47 ` [PATCH v2 23/74] semihosting: Split out semihost_sys_read Richard Henderson
@ 2022-05-03 19:47 ` Richard Henderson
  2022-05-03 19:47 ` [PATCH v2 25/74] semihosting: Bound length for semihost_sys_{read, write} Richard Henderson
                   ` (49 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:47 UTC (permalink / raw)
  To: qemu-devel

Split out the non-ARM specific portions of SYS_WRITE to a
reusable function.  This handles all GuestFD.  This removes
the last use of common_semi_syscall_len.

Note that gdb_do_syscall %x reads target_ulong, not int.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/semihosting/syscalls.h |  6 ++++
 semihosting/arm-compat-semi.c  | 52 +-------------------------------
 semihosting/syscalls.c         | 54 ++++++++++++++++++++++++++++++++++
 3 files changed, 61 insertions(+), 51 deletions(-)

diff --git a/include/semihosting/syscalls.h b/include/semihosting/syscalls.h
index 20da8138b0..2464467579 100644
--- a/include/semihosting/syscalls.h
+++ b/include/semihosting/syscalls.h
@@ -33,4 +33,10 @@ void semihost_sys_read(CPUState *cs, gdb_syscall_complete_cb complete,
 void semihost_sys_read_gf(CPUState *cs, gdb_syscall_complete_cb complete,
                           GuestFD *gf, target_ulong buf, target_ulong len);
 
+void semihost_sys_write(CPUState *cs, gdb_syscall_complete_cb complete,
+                        int fd, target_ulong buf, target_ulong len);
+
+void semihost_sys_write_gf(CPUState *cs, gdb_syscall_complete_cb complete,
+                           GuestFD *gf, target_ulong buf, target_ulong len);
+
 #endif /* SEMIHOSTING_SYSCALLS_H */
diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index 7b6df09f35..12b2c2b0f7 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -217,8 +217,6 @@ static inline uint32_t get_swi_errno(CPUState *cs)
 #endif
 }
 
-static target_ulong common_semi_syscall_len;
-
 static void common_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
 {
     if (err) {
@@ -232,9 +230,6 @@ static void common_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
         /* Fixup syscalls that use nonstardard return conventions.  */
         target_ulong reg0 = common_semi_arg(cs, 0);
         switch (reg0) {
-        case TARGET_SYS_WRITE:
-            ret = common_semi_syscall_len - ret;
-            break;
         case TARGET_SYS_SEEK:
             ret = 0;
             break;
@@ -294,30 +289,10 @@ common_semi_flen_cb(CPUState *cs, target_ulong ret, target_ulong err)
  * do the work and return the required return value to the guest
  * via common_semi_cb.
  */
-typedef void sys_writefn(CPUState *cs, GuestFD *gf,
-                         target_ulong buf, uint32_t len);
 typedef void sys_isattyfn(CPUState *cs, GuestFD *gf);
 typedef void sys_seekfn(CPUState *cs, GuestFD *gf, target_ulong offset);
 typedef void sys_flenfn(CPUState *cs, GuestFD *gf);
 
-static void host_writefn(CPUState *cs, GuestFD *gf,
-                         target_ulong buf, uint32_t len)
-{
-    CPUArchState *env = cs->env_ptr;
-    uint32_t ret = 0;
-    char *s = lock_user(VERIFY_READ, buf, len, 1);
-    (void) env; /* Used in arm softmmu lock_user implicitly */
-    if (s) {
-        ret = write(gf->hostfd, s, len);
-        unlock_user(s, buf, 0);
-        if (ret == (uint32_t)-1) {
-            ret = 0;
-        }
-    }
-    /* Return bytes not written, on error as well. */
-    common_semi_cb(cs, len - ret, 0);
-}
-
 static void host_isattyfn(CPUState *cs, GuestFD *gf)
 {
     common_semi_cb(cs, isatty(gf->hostfd), 0);
@@ -340,13 +315,6 @@ static void host_flenfn(CPUState *cs, GuestFD *gf)
     }
 }
 
-static void gdb_writefn(CPUState *cs, GuestFD *gf,
-                        target_ulong buf, uint32_t len)
-{
-    common_semi_syscall_len = len;
-    gdb_do_syscall(common_semi_cb, "write,%x,%x,%x", gf->hostfd, buf, len);
-}
-
 static void gdb_isattyfn(CPUState *cs, GuestFD *gf)
 {
     gdb_do_syscall(common_semi_cb, "isatty,%x", gf->hostfd);
@@ -380,13 +348,6 @@ static const uint8_t featurefile_data[] = {
     SH_EXT_EXIT_EXTENDED | SH_EXT_STDOUT_STDERR, /* Feature byte 0 */
 };
 
-static void staticfile_writefn(CPUState *cs, GuestFD *gf,
-                               target_ulong buf, uint32_t len)
-{
-    /* This fd can never be open for writing */
-    common_semi_cb(cs, -1, EBADF);
-}
-
 static void staticfile_isattyfn(CPUState *cs, GuestFD *gf)
 {
     common_semi_cb(cs, 0, 0);
@@ -404,7 +365,6 @@ static void staticfile_flenfn(CPUState *cs, GuestFD *gf)
 }
 
 typedef struct GuestFDFunctions {
-    sys_writefn *writefn;
     sys_isattyfn *isattyfn;
     sys_seekfn *seekfn;
     sys_flenfn *flenfn;
@@ -412,19 +372,16 @@ typedef struct GuestFDFunctions {
 
 static const GuestFDFunctions guestfd_fns[] = {
     [GuestFDHost] = {
-        .writefn = host_writefn,
         .isattyfn = host_isattyfn,
         .seekfn = host_seekfn,
         .flenfn = host_flenfn,
     },
     [GuestFDGDB] = {
-        .writefn = gdb_writefn,
         .isattyfn = gdb_isattyfn,
         .seekfn = gdb_seekfn,
         .flenfn = gdb_flenfn,
     },
     [GuestFDStatic] = {
-        .writefn = staticfile_writefn,
         .isattyfn = staticfile_isattyfn,
         .seekfn = staticfile_seekfn,
         .flenfn = staticfile_flenfn,
@@ -449,7 +406,6 @@ void do_common_semihosting(CPUState *cs)
     char * s;
     int nr;
     uint32_t ret;
-    uint32_t len;
     GuestFD *gf;
     int64_t elapsed;
 
@@ -530,13 +486,7 @@ void do_common_semihosting(CPUState *cs)
         GET_ARG(0);
         GET_ARG(1);
         GET_ARG(2);
-        len = arg2;
-
-        gf = get_guestfd(arg0);
-        if (!gf) {
-            goto do_badf;
-        }
-        guestfd_fns[gf->type].writefn(cs, gf, arg1, len);
+        semihost_sys_write(cs, common_semi_rw_cb, arg0, arg1, arg2);
         break;
 
     case TARGET_SYS_READ:
diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c
index 7c18f77898..db4561b798 100644
--- a/semihosting/syscalls.c
+++ b/semihosting/syscalls.c
@@ -137,6 +137,13 @@ static void gdb_read(CPUState *cs, gdb_syscall_complete_cb complete,
                    (target_ulong)gf->hostfd, buf, len);
 }
 
+static void gdb_write(CPUState *cs, gdb_syscall_complete_cb complete,
+                      GuestFD *gf, target_ulong buf, target_ulong len)
+{
+    gdb_do_syscall(complete, "write,%x,%x,%x",
+                   (target_ulong)gf->hostfd, buf, len);
+}
+
 /*
  * Host semihosting syscall implementations.
  */
@@ -223,6 +230,22 @@ static void host_read(CPUState *cs, gdb_syscall_complete_cb complete,
     }
 }
 
+static void host_write(CPUState *cs, gdb_syscall_complete_cb complete,
+                       GuestFD *gf, target_ulong buf, target_ulong len)
+{
+    CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
+    void *ptr = lock_user(VERIFY_READ, buf, len, 1);
+    ssize_t ret;
+
+    if (!ptr) {
+        complete(cs, -1, GDB_EFAULT);
+        return;
+    }
+    ret = write(gf->hostfd, ptr, len);
+    complete(cs, ret, ret == -1 ? errno_for_gdb() : 0);
+    unlock_user(ptr, buf, 0);
+}
+
 /*
  * Static file semihosting syscall implementations.
  */
@@ -316,3 +339,34 @@ void semihost_sys_read(CPUState *cs, gdb_syscall_complete_cb complete,
         complete(cs, -1, GDB_EBADF);
     }
 }
+
+void semihost_sys_write_gf(CPUState *cs, gdb_syscall_complete_cb complete,
+                           GuestFD *gf, target_ulong buf, target_ulong len)
+{
+    switch (gf->type) {
+    case GuestFDGDB:
+        gdb_write(cs, complete, gf, buf, len);
+        break;
+    case GuestFDHost:
+        host_write(cs, complete, gf, buf, len);
+        break;
+    case GuestFDStatic:
+        /* Static files are never open for writing: EBADF. */
+        complete(cs, -1, GDB_EBADF);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+}
+
+void semihost_sys_write(CPUState *cs, gdb_syscall_complete_cb complete,
+                        int fd, target_ulong buf, target_ulong len)
+{
+    GuestFD *gf = get_guestfd(fd);
+
+    if (gf) {
+        semihost_sys_write_gf(cs, complete, gf, buf, len);
+    } else {
+        complete(cs, -1, GDB_EBADF);
+    }
+}
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 25/74] semihosting: Bound length for semihost_sys_{read, write}
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (23 preceding siblings ...)
  2022-05-03 19:47 ` [PATCH v2 24/74] semihosting: Split out semihost_sys_write Richard Henderson
@ 2022-05-03 19:47 ` Richard Henderson
  2022-05-03 19:47 ` [PATCH v2 26/74] semihosting: Split out semihost_sys_lseek Richard Henderson
                   ` (48 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:47 UTC (permalink / raw)
  To: qemu-devel

Fixes a minor bug in which a 64-bit guest on a 32-bit host could
truncate the length.  This would only ever cause a problem if
there were no bits set in the low 32, so that it truncates to 0.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 semihosting/syscalls.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c
index db4561b798..a5623ebf0f 100644
--- a/semihosting/syscalls.c
+++ b/semihosting/syscalls.c
@@ -313,6 +313,14 @@ void semihost_sys_close(CPUState *cs, gdb_syscall_complete_cb complete, int fd)
 void semihost_sys_read_gf(CPUState *cs, gdb_syscall_complete_cb complete,
                           GuestFD *gf, target_ulong buf, target_ulong len)
 {
+    /*
+     * Bound length for 64-bit guests on 32-bit hosts, not overlowing ssize_t.
+     * Note the Linux kernel does this with MAX_RW_COUNT, so it's not a bad
+     * idea to do this unconditionally.
+     */
+    if (len > INT32_MAX) {
+        len = INT32_MAX;
+    }
     switch (gf->type) {
     case GuestFDGDB:
         gdb_read(cs, complete, gf, buf, len);
@@ -343,6 +351,14 @@ void semihost_sys_read(CPUState *cs, gdb_syscall_complete_cb complete,
 void semihost_sys_write_gf(CPUState *cs, gdb_syscall_complete_cb complete,
                            GuestFD *gf, target_ulong buf, target_ulong len)
 {
+    /*
+     * Bound length for 64-bit guests on 32-bit hosts, not overlowing ssize_t.
+     * Note the Linux kernel does this with MAX_RW_COUNT, so it's not a bad
+     * idea to do this unconditionally.
+     */
+    if (len > INT32_MAX) {
+        len = INT32_MAX;
+    }
     switch (gf->type) {
     case GuestFDGDB:
         gdb_write(cs, complete, gf, buf, len);
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 26/74] semihosting: Split out semihost_sys_lseek
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (24 preceding siblings ...)
  2022-05-03 19:47 ` [PATCH v2 25/74] semihosting: Bound length for semihost_sys_{read, write} Richard Henderson
@ 2022-05-03 19:47 ` Richard Henderson
  2022-05-03 19:47 ` [PATCH v2 27/74] semihosting: Split out semihost_sys_isatty Richard Henderson
                   ` (47 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:47 UTC (permalink / raw)
  To: qemu-devel

Split out the non-ARM specific portions of SYS_SEEK to a
reusable function.  This handles all GuestFD.  Isolate the
curious ARM-specific return value processing to a new
callback, common_semi_seek_cb.

Expand the internal type of the offset to int64_t, and
provide the whence argument, which will be required by
m68k and nios2 semihosting.

Note that gdb_do_syscall %x reads target_ulong, not int.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/exec/gdbstub.h         |  5 +++
 include/semihosting/syscalls.h |  3 ++
 semihosting/arm-compat-semi.c  | 51 ++++++---------------
 semihosting/syscalls.c         | 81 ++++++++++++++++++++++++++++++++++
 4 files changed, 102 insertions(+), 38 deletions(-)

diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index 0a6e0d6eeb..056db1a0d0 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -42,6 +42,11 @@
 #define GDB_ENAMETOOLONG   91
 #define GDB_EUNKNOWN       9999
 
+/* For gdb file i/o remote protocol lseek whence. */
+#define GDB_SEEK_SET  0
+#define GDB_SEEK_CUR  1
+#define GDB_SEEK_END  2
+
 /* For gdb file i/o stat/fstat. */
 typedef uint32_t gdb_mode_t;
 typedef uint32_t gdb_time_t;
diff --git a/include/semihosting/syscalls.h b/include/semihosting/syscalls.h
index 2464467579..841a93d25b 100644
--- a/include/semihosting/syscalls.h
+++ b/include/semihosting/syscalls.h
@@ -39,4 +39,7 @@ void semihost_sys_write(CPUState *cs, gdb_syscall_complete_cb complete,
 void semihost_sys_write_gf(CPUState *cs, gdb_syscall_complete_cb complete,
                            GuestFD *gf, target_ulong buf, target_ulong len);
 
+void semihost_sys_lseek(CPUState *cs, gdb_syscall_complete_cb complete,
+                        int fd, int64_t off, int gdb_whence);
+
 #endif /* SEMIHOSTING_SYSCALLS_H */
diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index 12b2c2b0f7..6f97977edf 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -226,16 +226,6 @@ static void common_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
 #else
         syscall_err = err;
 #endif
-    } else {
-        /* Fixup syscalls that use nonstardard return conventions.  */
-        target_ulong reg0 = common_semi_arg(cs, 0);
-        switch (reg0) {
-        case TARGET_SYS_SEEK:
-            ret = 0;
-            break;
-        default:
-            break;
-        }
     }
     common_semi_set_ret(cs, ret);
 }
@@ -258,6 +248,18 @@ static void common_semi_rw_cb(CPUState *cs, target_ulong ret, target_ulong err)
     common_semi_set_ret(cs, arg2 - ret);
 }
 
+/*
+ * SYS_SEEK returns 0 on success, not the resulting offset.
+ */
+static void common_semi_seek_cb(CPUState *cs, target_ulong ret,
+                                target_ulong err)
+{
+    if (!err) {
+        ret = 0;
+    }
+    common_semi_cb(cs, ret, err);
+}
+
 /*
  * Return an address in target memory of 64 bytes where the remote
  * gdb should write its stat struct. (The format of this structure
@@ -290,7 +292,6 @@ common_semi_flen_cb(CPUState *cs, target_ulong ret, target_ulong err)
  * via common_semi_cb.
  */
 typedef void sys_isattyfn(CPUState *cs, GuestFD *gf);
-typedef void sys_seekfn(CPUState *cs, GuestFD *gf, target_ulong offset);
 typedef void sys_flenfn(CPUState *cs, GuestFD *gf);
 
 static void host_isattyfn(CPUState *cs, GuestFD *gf)
@@ -298,12 +299,6 @@ static void host_isattyfn(CPUState *cs, GuestFD *gf)
     common_semi_cb(cs, isatty(gf->hostfd), 0);
 }
 
-static void host_seekfn(CPUState *cs, GuestFD *gf, target_ulong offset)
-{
-    off_t ret = lseek(gf->hostfd, offset, SEEK_SET);
-    common_semi_cb(cs, ret, ret == -1 ? errno : 0);
-}
-
 static void host_flenfn(CPUState *cs, GuestFD *gf)
 {
     struct stat buf;
@@ -320,11 +315,6 @@ static void gdb_isattyfn(CPUState *cs, GuestFD *gf)
     gdb_do_syscall(common_semi_cb, "isatty,%x", gf->hostfd);
 }
 
-static void gdb_seekfn(CPUState *cs, GuestFD *gf, target_ulong offset)
-{
-    gdb_do_syscall(common_semi_cb, "lseek,%x,%x,0", gf->hostfd, offset);
-}
-
 static void gdb_flenfn(CPUState *cs, GuestFD *gf)
 {
     gdb_do_syscall(common_semi_flen_cb, "fstat,%x,%x",
@@ -353,12 +343,6 @@ static void staticfile_isattyfn(CPUState *cs, GuestFD *gf)
     common_semi_cb(cs, 0, 0);
 }
 
-static void staticfile_seekfn(CPUState *cs, GuestFD *gf, target_ulong offset)
-{
-    gf->staticfile.off = offset;
-    common_semi_cb(cs, 0, 0);
-}
-
 static void staticfile_flenfn(CPUState *cs, GuestFD *gf)
 {
     common_semi_cb(cs, gf->staticfile.len, 0);
@@ -366,24 +350,20 @@ static void staticfile_flenfn(CPUState *cs, GuestFD *gf)
 
 typedef struct GuestFDFunctions {
     sys_isattyfn *isattyfn;
-    sys_seekfn *seekfn;
     sys_flenfn *flenfn;
 } GuestFDFunctions;
 
 static const GuestFDFunctions guestfd_fns[] = {
     [GuestFDHost] = {
         .isattyfn = host_isattyfn,
-        .seekfn = host_seekfn,
         .flenfn = host_flenfn,
     },
     [GuestFDGDB] = {
         .isattyfn = gdb_isattyfn,
-        .seekfn = gdb_seekfn,
         .flenfn = gdb_flenfn,
     },
     [GuestFDStatic] = {
         .isattyfn = staticfile_isattyfn,
-        .seekfn = staticfile_seekfn,
         .flenfn = staticfile_flenfn,
     },
 };
@@ -519,12 +499,7 @@ void do_common_semihosting(CPUState *cs)
     case TARGET_SYS_SEEK:
         GET_ARG(0);
         GET_ARG(1);
-
-        gf = get_guestfd(arg0);
-        if (!gf) {
-            goto do_badf;
-        }
-        guestfd_fns[gf->type].seekfn(cs, gf, arg1);
+        semihost_sys_lseek(cs, common_semi_seek_cb, arg0, arg1, GDB_SEEK_SET);
         break;
 
     case TARGET_SYS_FLEN:
diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c
index a5623ebf0f..db8891535b 100644
--- a/semihosting/syscalls.c
+++ b/semihosting/syscalls.c
@@ -144,6 +144,13 @@ static void gdb_write(CPUState *cs, gdb_syscall_complete_cb complete,
                    (target_ulong)gf->hostfd, buf, len);
 }
 
+static void gdb_lseek(CPUState *cs, gdb_syscall_complete_cb complete,
+                      GuestFD *gf, int64_t off, int gdb_whence)
+{
+    gdb_do_syscall(complete, "lseek,%x,%lx,%x",
+                   (target_ulong)gf->hostfd, off, (target_ulong)gdb_whence);
+}
+
 /*
  * Host semihosting syscall implementations.
  */
@@ -246,6 +253,29 @@ static void host_write(CPUState *cs, gdb_syscall_complete_cb complete,
     unlock_user(ptr, buf, 0);
 }
 
+static void host_lseek(CPUState *cs, gdb_syscall_complete_cb complete,
+                       GuestFD *gf, int64_t off, int whence)
+{
+    /* So far, all hosts use the same values. */
+    QEMU_BUILD_BUG_ON(GDB_SEEK_SET != SEEK_SET);
+    QEMU_BUILD_BUG_ON(GDB_SEEK_CUR != SEEK_CUR);
+    QEMU_BUILD_BUG_ON(GDB_SEEK_END != SEEK_END);
+
+    off_t ret = off;
+    int err = 0;
+
+    if (ret == off) {
+        ret = lseek(gf->hostfd, ret, whence);
+        if (ret == -1) {
+            err = errno_for_gdb();
+        }
+    } else {
+        ret = -1;
+        err = GDB_EINVAL;
+    }
+    complete(cs, ret, err);
+}
+
 /*
  * Static file semihosting syscall implementations.
  */
@@ -271,6 +301,33 @@ static void staticfile_read(CPUState *cs, gdb_syscall_complete_cb complete,
     unlock_user(ptr, buf, len);
 }
 
+static void staticfile_lseek(CPUState *cs, gdb_syscall_complete_cb complete,
+                             GuestFD *gf, int64_t off, int gdb_whence)
+{
+    int64_t ret;
+
+    switch (gdb_whence) {
+    case GDB_SEEK_SET:
+        ret = off;
+        break;
+    case GDB_SEEK_CUR:
+        ret = gf->staticfile.off + off;
+        break;
+    case GDB_SEEK_END:
+        ret = gf->staticfile.len - off;
+        break;
+    default:
+        ret = -1;
+        break;
+    }
+    if (ret >= 0 && ret <= gf->staticfile.len) {
+        gf->staticfile.off = ret;
+        complete(cs, ret, 0);
+    } else {
+        complete(cs, -1, EINVAL);
+    }
+}
+
 /*
  * Syscall entry points.
  */
@@ -386,3 +443,27 @@ void semihost_sys_write(CPUState *cs, gdb_syscall_complete_cb complete,
         complete(cs, -1, GDB_EBADF);
     }
 }
+
+void semihost_sys_lseek(CPUState *cs, gdb_syscall_complete_cb complete,
+                        int fd, int64_t off, int gdb_whence)
+{
+    GuestFD *gf = get_guestfd(fd);
+
+    if (!gf) {
+        complete(cs, -1, GDB_EBADF);
+        return;
+    }
+    switch (gf->type) {
+    case GuestFDGDB:
+        gdb_lseek(cs, complete, gf, off, gdb_whence);
+        return;
+    case GuestFDHost:
+        host_lseek(cs, complete, gf, off, gdb_whence);
+        break;
+    case GuestFDStatic:
+        staticfile_lseek(cs, complete, gf, off, gdb_whence);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+}
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 27/74] semihosting: Split out semihost_sys_isatty
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (25 preceding siblings ...)
  2022-05-03 19:47 ` [PATCH v2 26/74] semihosting: Split out semihost_sys_lseek Richard Henderson
@ 2022-05-03 19:47 ` Richard Henderson
  2022-05-03 19:47 ` [PATCH v2 28/74] semihosting: Split out semihost_sys_flen Richard Henderson
                   ` (46 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:47 UTC (permalink / raw)
  To: qemu-devel

Split out the non-ARM specific portions of SYS_ISTTY to a
reusable function.  This handles all GuestFD.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/exec/gdbstub.h         |  1 +
 include/semihosting/syscalls.h |  3 +++
 semihosting/arm-compat-semi.c  | 27 +------------------------
 semihosting/syscalls.c         | 36 ++++++++++++++++++++++++++++++++++
 4 files changed, 41 insertions(+), 26 deletions(-)

diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index 056db1a0d0..fd4bc4e937 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -41,6 +41,7 @@
 #define GDB_EROFS          30
 #define GDB_ENAMETOOLONG   91
 #define GDB_EUNKNOWN       9999
+#define GDB_ENOTTY         GDB_EUNKNOWN
 
 /* For gdb file i/o remote protocol lseek whence. */
 #define GDB_SEEK_SET  0
diff --git a/include/semihosting/syscalls.h b/include/semihosting/syscalls.h
index 841a93d25b..c60ebafb85 100644
--- a/include/semihosting/syscalls.h
+++ b/include/semihosting/syscalls.h
@@ -42,4 +42,7 @@ void semihost_sys_write_gf(CPUState *cs, gdb_syscall_complete_cb complete,
 void semihost_sys_lseek(CPUState *cs, gdb_syscall_complete_cb complete,
                         int fd, int64_t off, int gdb_whence);
 
+void semihost_sys_isatty(CPUState *cs, gdb_syscall_complete_cb complete,
+                         int fd);
+
 #endif /* SEMIHOSTING_SYSCALLS_H */
diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index 6f97977edf..8fcef02386 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -291,14 +291,8 @@ common_semi_flen_cb(CPUState *cs, target_ulong ret, target_ulong err)
  * do the work and return the required return value to the guest
  * via common_semi_cb.
  */
-typedef void sys_isattyfn(CPUState *cs, GuestFD *gf);
 typedef void sys_flenfn(CPUState *cs, GuestFD *gf);
 
-static void host_isattyfn(CPUState *cs, GuestFD *gf)
-{
-    common_semi_cb(cs, isatty(gf->hostfd), 0);
-}
-
 static void host_flenfn(CPUState *cs, GuestFD *gf)
 {
     struct stat buf;
@@ -310,11 +304,6 @@ static void host_flenfn(CPUState *cs, GuestFD *gf)
     }
 }
 
-static void gdb_isattyfn(CPUState *cs, GuestFD *gf)
-{
-    gdb_do_syscall(common_semi_cb, "isatty,%x", gf->hostfd);
-}
-
 static void gdb_flenfn(CPUState *cs, GuestFD *gf)
 {
     gdb_do_syscall(common_semi_flen_cb, "fstat,%x,%x",
@@ -338,32 +327,23 @@ static const uint8_t featurefile_data[] = {
     SH_EXT_EXIT_EXTENDED | SH_EXT_STDOUT_STDERR, /* Feature byte 0 */
 };
 
-static void staticfile_isattyfn(CPUState *cs, GuestFD *gf)
-{
-    common_semi_cb(cs, 0, 0);
-}
-
 static void staticfile_flenfn(CPUState *cs, GuestFD *gf)
 {
     common_semi_cb(cs, gf->staticfile.len, 0);
 }
 
 typedef struct GuestFDFunctions {
-    sys_isattyfn *isattyfn;
     sys_flenfn *flenfn;
 } GuestFDFunctions;
 
 static const GuestFDFunctions guestfd_fns[] = {
     [GuestFDHost] = {
-        .isattyfn = host_isattyfn,
         .flenfn = host_flenfn,
     },
     [GuestFDGDB] = {
-        .isattyfn = gdb_isattyfn,
         .flenfn = gdb_flenfn,
     },
     [GuestFDStatic] = {
-        .isattyfn = staticfile_isattyfn,
         .flenfn = staticfile_flenfn,
     },
 };
@@ -488,12 +468,7 @@ void do_common_semihosting(CPUState *cs)
 
     case TARGET_SYS_ISTTY:
         GET_ARG(0);
-
-        gf = get_guestfd(arg0);
-        if (!gf) {
-            goto do_badf;
-        }
-        guestfd_fns[gf->type].isattyfn(cs, gf);
+        semihost_sys_isatty(cs, common_semi_cb, arg0);
         break;
 
     case TARGET_SYS_SEEK:
diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c
index db8891535b..702541b270 100644
--- a/semihosting/syscalls.c
+++ b/semihosting/syscalls.c
@@ -151,6 +151,12 @@ static void gdb_lseek(CPUState *cs, gdb_syscall_complete_cb complete,
                    (target_ulong)gf->hostfd, off, (target_ulong)gdb_whence);
 }
 
+static void gdb_isatty(CPUState *cs, gdb_syscall_complete_cb complete,
+                       GuestFD *gf)
+{
+    gdb_do_syscall(complete, "isatty,%x", (target_ulong)gf->hostfd);
+}
+
 /*
  * Host semihosting syscall implementations.
  */
@@ -276,6 +282,13 @@ static void host_lseek(CPUState *cs, gdb_syscall_complete_cb complete,
     complete(cs, ret, err);
 }
 
+static void host_isatty(CPUState *cs, gdb_syscall_complete_cb complete,
+                        GuestFD *gf)
+{
+    int ret = isatty(gf->hostfd);
+    complete(cs, ret, ret ? 0 : errno_for_gdb());
+}
+
 /*
  * Static file semihosting syscall implementations.
  */
@@ -467,3 +480,26 @@ void semihost_sys_lseek(CPUState *cs, gdb_syscall_complete_cb complete,
         g_assert_not_reached();
     }
 }
+
+void semihost_sys_isatty(CPUState *cs, gdb_syscall_complete_cb complete, int fd)
+{
+    GuestFD *gf = get_guestfd(fd);
+
+    if (!gf) {
+        complete(cs, 0, GDB_EBADF);
+        return;
+    }
+    switch (gf->type) {
+    case GuestFDGDB:
+        gdb_isatty(cs, complete, gf);
+        break;
+    case GuestFDHost:
+        host_isatty(cs, complete, gf);
+        break;
+    case GuestFDStatic:
+        complete(cs, 0, GDB_ENOTTY);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+}
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 28/74] semihosting: Split out semihost_sys_flen
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (26 preceding siblings ...)
  2022-05-03 19:47 ` [PATCH v2 27/74] semihosting: Split out semihost_sys_isatty Richard Henderson
@ 2022-05-03 19:47 ` Richard Henderson
  2022-05-03 19:47 ` [PATCH v2 29/74] semihosting: Split out semihost_sys_remove Richard Henderson
                   ` (45 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:47 UTC (permalink / raw)
  To: qemu-devel

The ARM-specific SYS_FLEN isn't really something that can be
reused by other semihosting apis, but there are parts that can
reused for the implementation of semihost_sys_fstat.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/exec/gdbstub.h         |  1 +
 include/semihosting/syscalls.h |  4 ++
 semihosting/arm-compat-semi.c  | 83 ++++++++--------------------------
 semihosting/syscalls.c         | 49 ++++++++++++++++++++
 4 files changed, 73 insertions(+), 64 deletions(-)

diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index fd4bc4e937..8e9cdcb1c1 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -42,6 +42,7 @@
 #define GDB_ENAMETOOLONG   91
 #define GDB_EUNKNOWN       9999
 #define GDB_ENOTTY         GDB_EUNKNOWN
+#define GDB_EOVERFLOW      GDB_EUNKNOWN
 
 /* For gdb file i/o remote protocol lseek whence. */
 #define GDB_SEEK_SET  0
diff --git a/include/semihosting/syscalls.h b/include/semihosting/syscalls.h
index c60ebafb85..1ae5ba6716 100644
--- a/include/semihosting/syscalls.h
+++ b/include/semihosting/syscalls.h
@@ -45,4 +45,8 @@ void semihost_sys_lseek(CPUState *cs, gdb_syscall_complete_cb complete,
 void semihost_sys_isatty(CPUState *cs, gdb_syscall_complete_cb complete,
                          int fd);
 
+void semihost_sys_flen(CPUState *cs, gdb_syscall_complete_cb fstat_cb,
+                       gdb_syscall_complete_cb flen_cb,
+                       int fd, target_ulong fstat_addr);
+
 #endif /* SEMIHOSTING_SYSCALLS_H */
diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index 8fcef02386..ad43bc8b0d 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -273,41 +273,25 @@ static target_ulong common_semi_flen_buf(CPUState *cs)
 }
 
 static void
-common_semi_flen_cb(CPUState *cs, target_ulong ret, target_ulong err)
+common_semi_flen_fstat_cb(CPUState *cs, target_ulong ret, target_ulong err)
 {
-    /* The size is always stored in big-endian order, extract the value. */
-    uint64_t size;
-    cpu_memory_rw_debug(cs, common_semi_flen_buf(cs) +
-                        offsetof(struct gdb_stat, gdb_st_size),
-                        &size, 8, 0);
-    size = be64_to_cpu(size);
-    common_semi_cb(cs, -1, err);
-    common_semi_set_ret(cs, size);
-}
-
-/*
- * Types for functions implementing various semihosting calls
- * for specific types of guest file descriptor. These must all
- * do the work and return the required return value to the guest
- * via common_semi_cb.
- */
-typedef void sys_flenfn(CPUState *cs, GuestFD *gf);
-
-static void host_flenfn(CPUState *cs, GuestFD *gf)
-{
-    struct stat buf;
-
-    if (fstat(gf->hostfd, &buf)) {
-        common_semi_cb(cs, -1, errno);
-    } else {
-        common_semi_cb(cs, buf.st_size, 0);
+    if (!err) {
+        /* The size is always stored in big-endian order, extract the value. */
+        CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
+        uint64_t size;
+        if (get_user_u64(size, common_semi_flen_buf(cs) +
+                         offsetof(struct gdb_stat, gdb_st_size))) {
+            ret = -1, err = GDB_EFAULT;
+        } else {
+            /* Undo the tswap from get_user_u64, then swap from BE. */
+            size = be64_to_cpu(tswap64(size));
+            ret = size;
+            if (ret != size) {
+                ret = -1, err = GDB_EOVERFLOW;
+            }
+        }
     }
-}
-
-static void gdb_flenfn(CPUState *cs, GuestFD *gf)
-{
-    gdb_do_syscall(common_semi_flen_cb, "fstat,%x,%x",
-                   gf->hostfd, common_semi_flen_buf(cs));
+    common_semi_cb(cs, ret, err);
 }
 
 #define SHFB_MAGIC_0 0x53
@@ -327,27 +311,6 @@ static const uint8_t featurefile_data[] = {
     SH_EXT_EXIT_EXTENDED | SH_EXT_STDOUT_STDERR, /* Feature byte 0 */
 };
 
-static void staticfile_flenfn(CPUState *cs, GuestFD *gf)
-{
-    common_semi_cb(cs, gf->staticfile.len, 0);
-}
-
-typedef struct GuestFDFunctions {
-    sys_flenfn *flenfn;
-} GuestFDFunctions;
-
-static const GuestFDFunctions guestfd_fns[] = {
-    [GuestFDHost] = {
-        .flenfn = host_flenfn,
-    },
-    [GuestFDGDB] = {
-        .flenfn = gdb_flenfn,
-    },
-    [GuestFDStatic] = {
-        .flenfn = staticfile_flenfn,
-    },
-};
-
 /*
  * Do a semihosting call.
  *
@@ -366,7 +329,6 @@ void do_common_semihosting(CPUState *cs)
     char * s;
     int nr;
     uint32_t ret;
-    GuestFD *gf;
     int64_t elapsed;
 
     nr = common_semi_arg(cs, 0) & 0xffffffffU;
@@ -479,12 +441,8 @@ void do_common_semihosting(CPUState *cs)
 
     case TARGET_SYS_FLEN:
         GET_ARG(0);
-
-        gf = get_guestfd(arg0);
-        if (!gf) {
-            goto do_badf;
-        }
-        guestfd_fns[gf->type].flenfn(cs, gf);
+        semihost_sys_flen(cs, common_semi_flen_fstat_cb, common_semi_cb,
+                          arg0, common_semi_flen_buf(cs));
         break;
 
     case TARGET_SYS_TMPNAM:
@@ -806,9 +764,6 @@ void do_common_semihosting(CPUState *cs)
         cpu_dump_state(cs, stderr, 0);
         abort();
 
-    do_badf:
-        common_semi_cb(cs, -1, EBADF);
-        break;
     do_fault:
         common_semi_cb(cs, -1, EFAULT);
         break;
diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c
index 702541b270..1425156bf6 100644
--- a/semihosting/syscalls.c
+++ b/semihosting/syscalls.c
@@ -157,6 +157,12 @@ static void gdb_isatty(CPUState *cs, gdb_syscall_complete_cb complete,
     gdb_do_syscall(complete, "isatty,%x", (target_ulong)gf->hostfd);
 }
 
+static void gdb_fstat(CPUState *cs, gdb_syscall_complete_cb complete,
+                      GuestFD *gf, target_ulong addr)
+{
+    gdb_do_syscall(complete, "fstat,%x,%x", (target_ulong)gf->hostfd, addr);
+}
+
 /*
  * Host semihosting syscall implementations.
  */
@@ -289,6 +295,18 @@ static void host_isatty(CPUState *cs, gdb_syscall_complete_cb complete,
     complete(cs, ret, ret ? 0 : errno_for_gdb());
 }
 
+static void host_flen(CPUState *cs, gdb_syscall_complete_cb complete,
+                      GuestFD *gf)
+{
+    struct stat buf;
+
+    if (fstat(gf->hostfd, &buf) < 0) {
+        complete(cs, -1, errno_for_gdb());
+    } else {
+        complete(cs, buf.st_size, 0);
+    }
+}
+
 /*
  * Static file semihosting syscall implementations.
  */
@@ -341,6 +359,12 @@ static void staticfile_lseek(CPUState *cs, gdb_syscall_complete_cb complete,
     }
 }
 
+static void staticfile_flen(CPUState *cs, gdb_syscall_complete_cb complete,
+                            GuestFD *gf)
+{
+    complete(cs, gf->staticfile.len, 0);
+}
+
 /*
  * Syscall entry points.
  */
@@ -503,3 +527,28 @@ void semihost_sys_isatty(CPUState *cs, gdb_syscall_complete_cb complete, int fd)
         g_assert_not_reached();
     }
 }
+
+void semihost_sys_flen(CPUState *cs, gdb_syscall_complete_cb fstat_cb,
+                       gdb_syscall_complete_cb flen_cb, int fd,
+                       target_ulong fstat_addr)
+{
+    GuestFD *gf = get_guestfd(fd);
+
+    if (!gf) {
+        flen_cb(cs, -1, GDB_EBADF);
+        return;
+    }
+    switch (gf->type) {
+    case GuestFDGDB:
+        gdb_fstat(cs, fstat_cb, gf, fstat_addr);
+        break;
+    case GuestFDHost:
+        host_flen(cs, flen_cb, gf);
+        break;
+    case GuestFDStatic:
+        staticfile_flen(cs, flen_cb, gf);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+}
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 29/74] semihosting: Split out semihost_sys_remove
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (27 preceding siblings ...)
  2022-05-03 19:47 ` [PATCH v2 28/74] semihosting: Split out semihost_sys_flen Richard Henderson
@ 2022-05-03 19:47 ` Richard Henderson
  2022-05-03 19:47 ` [PATCH v2 30/74] semihosting: Split out semihost_sys_rename Richard Henderson
                   ` (44 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:47 UTC (permalink / raw)
  To: qemu-devel

Split out the non-ARM specific portions of SYS_REMOVE to a
reusable function.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/semihosting/syscalls.h |  3 +++
 semihosting/arm-compat-semi.c  | 13 +----------
 semihosting/syscalls.c         | 40 ++++++++++++++++++++++++++++++++++
 3 files changed, 44 insertions(+), 12 deletions(-)

diff --git a/include/semihosting/syscalls.h b/include/semihosting/syscalls.h
index 1ae5ba6716..748a4b5e47 100644
--- a/include/semihosting/syscalls.h
+++ b/include/semihosting/syscalls.h
@@ -49,4 +49,7 @@ void semihost_sys_flen(CPUState *cs, gdb_syscall_complete_cb fstat_cb,
                        gdb_syscall_complete_cb flen_cb,
                        int fd, target_ulong fstat_addr);
 
+void semihost_sys_remove(CPUState *cs, gdb_syscall_complete_cb complete,
+                         target_ulong fname, target_ulong fname_len);
+
 #endif /* SEMIHOSTING_SYSCALLS_H */
diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index ad43bc8b0d..9c98af19ca 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -473,18 +473,7 @@ void do_common_semihosting(CPUState *cs)
     case TARGET_SYS_REMOVE:
         GET_ARG(0);
         GET_ARG(1);
-        if (use_gdb_syscalls()) {
-            gdb_do_syscall(common_semi_cb, "unlink,%s",
-                           arg0, (int)arg1 + 1);
-            break;
-        }
-        s = lock_user_string(arg0);
-        if (!s) {
-            goto do_fault;
-        }
-        ret = remove(s);
-        unlock_user(s, arg0, 0);
-        common_semi_cb(cs, ret, ret ? errno : 0);
+        semihost_sys_remove(cs, common_semi_cb, arg0, arg1 + 1);
         break;
 
     case TARGET_SYS_RENAME:
diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c
index 1425156bf6..3464896281 100644
--- a/semihosting/syscalls.c
+++ b/semihosting/syscalls.c
@@ -163,6 +163,18 @@ static void gdb_fstat(CPUState *cs, gdb_syscall_complete_cb complete,
     gdb_do_syscall(complete, "fstat,%x,%x", (target_ulong)gf->hostfd, addr);
 }
 
+static void gdb_remove(CPUState *cs, gdb_syscall_complete_cb complete,
+                       target_ulong fname, target_ulong fname_len)
+{
+    int len = validate_strlen(cs, fname, fname_len);
+    if (len < 0) {
+        complete(cs, -1, -len);
+        return;
+    }
+
+    gdb_do_syscall(complete, "unlink,%s", fname, len);
+}
+
 /*
  * Host semihosting syscall implementations.
  */
@@ -307,6 +319,24 @@ static void host_flen(CPUState *cs, gdb_syscall_complete_cb complete,
     }
 }
 
+static void host_remove(CPUState *cs, gdb_syscall_complete_cb complete,
+                        target_ulong fname, target_ulong fname_len)
+{
+    CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
+    char *p;
+    int ret;
+
+    ret = validate_lock_user_string(&p, cs, fname, fname_len);
+    if (ret < 0) {
+        complete(cs, -1, -ret);
+        return;
+    }
+
+    ret = remove(p);
+    complete(cs, ret, ret ? errno_for_gdb() : 0);
+    unlock_user(p, fname, 0);
+}
+
 /*
  * Static file semihosting syscall implementations.
  */
@@ -552,3 +582,13 @@ void semihost_sys_flen(CPUState *cs, gdb_syscall_complete_cb fstat_cb,
         g_assert_not_reached();
     }
 }
+
+void semihost_sys_remove(CPUState *cs, gdb_syscall_complete_cb complete,
+                         target_ulong fname, target_ulong fname_len)
+{
+    if (use_gdb_syscalls()) {
+        gdb_remove(cs, complete, fname, fname_len);
+    } else {
+        host_remove(cs, complete, fname, fname_len);
+    }
+}
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 30/74] semihosting: Split out semihost_sys_rename
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (28 preceding siblings ...)
  2022-05-03 19:47 ` [PATCH v2 29/74] semihosting: Split out semihost_sys_remove Richard Henderson
@ 2022-05-03 19:47 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 31/74] semihosting: Split out semihost_sys_system Richard Henderson
                   ` (43 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:47 UTC (permalink / raw)
  To: qemu-devel

Split out the non-ARM specific portions of SYS_RENAME to a
reusable function.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/semihosting/syscalls.h |  4 +++
 semihosting/arm-compat-semi.c  | 21 +------------
 semihosting/syscalls.c         | 57 ++++++++++++++++++++++++++++++++++
 3 files changed, 62 insertions(+), 20 deletions(-)

diff --git a/include/semihosting/syscalls.h b/include/semihosting/syscalls.h
index 748a4b5e47..21430aa0ef 100644
--- a/include/semihosting/syscalls.h
+++ b/include/semihosting/syscalls.h
@@ -52,4 +52,8 @@ void semihost_sys_flen(CPUState *cs, gdb_syscall_complete_cb fstat_cb,
 void semihost_sys_remove(CPUState *cs, gdb_syscall_complete_cb complete,
                          target_ulong fname, target_ulong fname_len);
 
+void semihost_sys_rename(CPUState *cs, gdb_syscall_complete_cb complete,
+                         target_ulong oname, target_ulong oname_len,
+                         target_ulong nname, target_ulong nname_len);
+
 #endif /* SEMIHOSTING_SYSCALLS_H */
diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index 9c98af19ca..f554f4761f 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -481,26 +481,7 @@ void do_common_semihosting(CPUState *cs)
         GET_ARG(1);
         GET_ARG(2);
         GET_ARG(3);
-        if (use_gdb_syscalls()) {
-            gdb_do_syscall(common_semi_cb, "rename,%s,%s",
-                           arg0, (int)arg1 + 1, arg2, (int)arg3 + 1);
-        } else {
-            char *s2;
-
-            s = lock_user_string(arg0);
-            if (!s) {
-                goto do_fault;
-            }
-            s2 = lock_user_string(arg2);
-            if (!s2) {
-                unlock_user(s, arg0, 0);
-                goto do_fault;
-            }
-            ret = rename(s, s2);
-            unlock_user(s2, arg2, 0);
-            unlock_user(s, arg0, 0);
-            common_semi_cb(cs, ret, ret ? errno : 0);
-        }
+        semihost_sys_rename(cs, common_semi_cb, arg0, arg1 + 1, arg2, arg3 + 1);
         break;
 
     case TARGET_SYS_CLOCK:
diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c
index 3464896281..96d823e8b3 100644
--- a/semihosting/syscalls.c
+++ b/semihosting/syscalls.c
@@ -175,6 +175,26 @@ static void gdb_remove(CPUState *cs, gdb_syscall_complete_cb complete,
     gdb_do_syscall(complete, "unlink,%s", fname, len);
 }
 
+static void gdb_rename(CPUState *cs, gdb_syscall_complete_cb complete,
+                       target_ulong oname, target_ulong oname_len,
+                       target_ulong nname, target_ulong nname_len)
+{
+    int olen, nlen;
+
+    olen = validate_strlen(cs, oname, oname_len);
+    if (olen < 0) {
+        complete(cs, -1, -olen);
+        return;
+    }
+    nlen = validate_strlen(cs, nname, nname_len);
+    if (nlen < 0) {
+        complete(cs, -1, -nlen);
+        return;
+    }
+
+    gdb_do_syscall(complete, "rename,%s,%s", oname, olen, nname, nlen);
+}
+
 /*
  * Host semihosting syscall implementations.
  */
@@ -337,6 +357,32 @@ static void host_remove(CPUState *cs, gdb_syscall_complete_cb complete,
     unlock_user(p, fname, 0);
 }
 
+static void host_rename(CPUState *cs, gdb_syscall_complete_cb complete,
+                        target_ulong oname, target_ulong oname_len,
+                        target_ulong nname, target_ulong nname_len)
+{
+    CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
+    char *ostr, *nstr;
+    int ret;
+
+    ret = validate_lock_user_string(&ostr, cs, oname, oname_len);
+    if (ret < 0) {
+        complete(cs, -1, -ret);
+        return;
+    }
+    ret = validate_lock_user_string(&nstr, cs, nname, nname_len);
+    if (ret < 0) {
+        unlock_user(ostr, oname, 0);
+        complete(cs, -1, -ret);
+        return;
+    }
+
+    ret = rename(ostr, nstr);
+    complete(cs, ret, ret ? errno_for_gdb() : 0);
+    unlock_user(ostr, oname, 0);
+    unlock_user(nstr, nname, 0);
+}
+
 /*
  * Static file semihosting syscall implementations.
  */
@@ -592,3 +638,14 @@ void semihost_sys_remove(CPUState *cs, gdb_syscall_complete_cb complete,
         host_remove(cs, complete, fname, fname_len);
     }
 }
+
+void semihost_sys_rename(CPUState *cs, gdb_syscall_complete_cb complete,
+                         target_ulong oname, target_ulong oname_len,
+                         target_ulong nname, target_ulong nname_len)
+{
+    if (use_gdb_syscalls()) {
+        gdb_rename(cs, complete, oname, oname_len, nname, nname_len);
+    } else {
+        host_rename(cs, complete, oname, oname_len, nname, nname_len);
+    }
+}
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 31/74] semihosting: Split out semihost_sys_system
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (29 preceding siblings ...)
  2022-05-03 19:47 ` [PATCH v2 30/74] semihosting: Split out semihost_sys_rename Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 32/74] semihosting: Create semihost_sys_{stat,fstat} Richard Henderson
                   ` (42 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

Split out the non-ARM specific portions of SYS_SYSTEM to a
reusable function.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/semihosting/syscalls.h |  3 +++
 semihosting/arm-compat-semi.c  | 12 +---------
 semihosting/syscalls.c         | 40 ++++++++++++++++++++++++++++++++++
 3 files changed, 44 insertions(+), 11 deletions(-)

diff --git a/include/semihosting/syscalls.h b/include/semihosting/syscalls.h
index 21430aa0ef..c9f9e66be1 100644
--- a/include/semihosting/syscalls.h
+++ b/include/semihosting/syscalls.h
@@ -56,4 +56,7 @@ void semihost_sys_rename(CPUState *cs, gdb_syscall_complete_cb complete,
                          target_ulong oname, target_ulong oname_len,
                          target_ulong nname, target_ulong nname_len);
 
+void semihost_sys_system(CPUState *cs, gdb_syscall_complete_cb complete,
+                         target_ulong cmd, target_ulong cmd_len);
+
 #endif /* SEMIHOSTING_SYSCALLS_H */
diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index f554f4761f..a7520d6f41 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -496,17 +496,7 @@ void do_common_semihosting(CPUState *cs)
     case TARGET_SYS_SYSTEM:
         GET_ARG(0);
         GET_ARG(1);
-        if (use_gdb_syscalls()) {
-            gdb_do_syscall(common_semi_cb, "system,%s", arg0, (int)arg1 + 1);
-            break;
-        }
-        s = lock_user_string(arg0);
-        if (!s) {
-            goto do_fault;
-        }
-        ret = system(s);
-        unlock_user(s, arg0, 0);
-        common_semi_cb(cs, ret, ret == -1 ? errno : 0);
+        semihost_sys_system(cs, common_semi_cb, arg0, arg1 + 1);
         break;
 
     case TARGET_SYS_ERRNO:
diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c
index 96d823e8b3..b6c395af22 100644
--- a/semihosting/syscalls.c
+++ b/semihosting/syscalls.c
@@ -195,6 +195,18 @@ static void gdb_rename(CPUState *cs, gdb_syscall_complete_cb complete,
     gdb_do_syscall(complete, "rename,%s,%s", oname, olen, nname, nlen);
 }
 
+static void gdb_system(CPUState *cs, gdb_syscall_complete_cb complete,
+                       target_ulong cmd, target_ulong cmd_len)
+{
+    int len = validate_strlen(cs, cmd, cmd_len);
+    if (len < 0) {
+        complete(cs, -1, -len);
+        return;
+    }
+
+    gdb_do_syscall(complete, "system,%s", cmd, len);
+}
+
 /*
  * Host semihosting syscall implementations.
  */
@@ -383,6 +395,24 @@ static void host_rename(CPUState *cs, gdb_syscall_complete_cb complete,
     unlock_user(nstr, nname, 0);
 }
 
+static void host_system(CPUState *cs, gdb_syscall_complete_cb complete,
+                        target_ulong cmd, target_ulong cmd_len)
+{
+    CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
+    char *p;
+    int ret;
+
+    ret = validate_lock_user_string(&p, cs, cmd, cmd_len);
+    if (ret < 0) {
+        complete(cs, -1, -ret);
+        return;
+    }
+
+    ret = system(p);
+    complete(cs, ret, ret == -1 ? errno_for_gdb() : 0);
+    unlock_user(p, cmd, 0);
+}
+
 /*
  * Static file semihosting syscall implementations.
  */
@@ -649,3 +679,13 @@ void semihost_sys_rename(CPUState *cs, gdb_syscall_complete_cb complete,
         host_rename(cs, complete, oname, oname_len, nname, nname_len);
     }
 }
+
+void semihost_sys_system(CPUState *cs, gdb_syscall_complete_cb complete,
+                         target_ulong cmd, target_ulong cmd_len)
+{
+    if (use_gdb_syscalls()) {
+        gdb_system(cs, complete, cmd, cmd_len);
+    } else {
+        host_system(cs, complete, cmd, cmd_len);
+    }
+}
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 32/74] semihosting: Create semihost_sys_{stat,fstat}
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (30 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 31/74] semihosting: Split out semihost_sys_system Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 33/74] semihosting: Create semihost_sys_gettimeofday Richard Henderson
                   ` (41 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

These syscalls will be used by m68k and nios2 semihosting.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/semihosting/syscalls.h |   7 ++
 semihosting/syscalls.c         | 137 +++++++++++++++++++++++++++++++++
 2 files changed, 144 insertions(+)

diff --git a/include/semihosting/syscalls.h b/include/semihosting/syscalls.h
index c9f9e66be1..ecc97751a9 100644
--- a/include/semihosting/syscalls.h
+++ b/include/semihosting/syscalls.h
@@ -49,6 +49,13 @@ void semihost_sys_flen(CPUState *cs, gdb_syscall_complete_cb fstat_cb,
                        gdb_syscall_complete_cb flen_cb,
                        int fd, target_ulong fstat_addr);
 
+void semihost_sys_fstat(CPUState *cs, gdb_syscall_complete_cb complete,
+                        int fd, target_ulong addr);
+
+void semihost_sys_stat(CPUState *cs, gdb_syscall_complete_cb complete,
+                       target_ulong fname, target_ulong fname_len,
+                       target_ulong addr);
+
 void semihost_sys_remove(CPUState *cs, gdb_syscall_complete_cb complete,
                          target_ulong fname, target_ulong fname_len);
 
diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c
index b6c395af22..7bc2640512 100644
--- a/semihosting/syscalls.c
+++ b/semihosting/syscalls.c
@@ -93,6 +93,52 @@ static int errno_for_gdb(void)
 #undef E
 }
 
+/*
+ * TODO: Note that gdb always stores the stat structure big-endian.
+ * So far, that's ok, as the only two targets using this are also
+ * big-endian.  Until we do something with gdb, also produce the
+ * same big-endian result from the host.
+ */
+static int copy_stat_to_user(CPUState *cs, target_ulong addr,
+                             const struct stat *s)
+{
+    CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
+    struct gdb_stat *p;
+
+    if (s->st_dev != (uint32_t)s->st_dev ||
+        s->st_ino != (uint32_t)s->st_ino) {
+        return -GDB_EOVERFLOW;
+    }
+
+    p = lock_user(VERIFY_WRITE, addr, sizeof(struct gdb_stat), 0);
+    if (!p) {
+        return -GDB_EFAULT;
+    }
+
+    p->gdb_st_dev = cpu_to_be32(s->st_dev);
+    p->gdb_st_ino = cpu_to_be32(s->st_ino);
+    p->gdb_st_mode = cpu_to_be32(s->st_mode);
+    p->gdb_st_nlink = cpu_to_be32(s->st_nlink);
+    p->gdb_st_uid = cpu_to_be32(s->st_uid);
+    p->gdb_st_gid = cpu_to_be32(s->st_gid);
+    p->gdb_st_rdev = cpu_to_be32(s->st_rdev);
+    p->gdb_st_size = cpu_to_be64(s->st_size);
+#ifdef _WIN32
+    /* Windows stat is missing some fields.  */
+    p->gdb_st_blksize = 0;
+    p->gdb_st_blocks = 0;
+#else
+    p->gdb_st_blksize = cpu_to_be64(s->st_blksize);
+    p->gdb_st_blocks = cpu_to_be64(s->st_blocks);
+#endif
+    p->gdb_st_atime = cpu_to_be32(s->st_atime);
+    p->gdb_st_mtime = cpu_to_be32(s->st_mtime);
+    p->gdb_st_ctime = cpu_to_be32(s->st_ctime);
+
+    unlock_user(p, addr, sizeof(struct gdb_stat));
+    return 0;
+}
+
 /*
  * GDB semihosting syscall implementations.
  */
@@ -163,6 +209,19 @@ static void gdb_fstat(CPUState *cs, gdb_syscall_complete_cb complete,
     gdb_do_syscall(complete, "fstat,%x,%x", (target_ulong)gf->hostfd, addr);
 }
 
+static void gdb_stat(CPUState *cs, gdb_syscall_complete_cb complete,
+                     target_ulong fname, target_ulong fname_len,
+                     target_ulong addr)
+{
+    int len = validate_strlen(cs, fname, fname_len);
+    if (len < 0) {
+        complete(cs, -1, -len);
+        return;
+    }
+
+    gdb_do_syscall(complete, "stat,%s,%x", fname, len, addr);
+}
+
 static void gdb_remove(CPUState *cs, gdb_syscall_complete_cb complete,
                        target_ulong fname, target_ulong fname_len)
 {
@@ -351,6 +410,51 @@ static void host_flen(CPUState *cs, gdb_syscall_complete_cb complete,
     }
 }
 
+static void host_fstat(CPUState *cs, gdb_syscall_complete_cb complete,
+                       GuestFD *gf, target_ulong addr)
+{
+    struct stat buf;
+    int ret;
+
+    ret = fstat(gf->hostfd, &buf);
+    if (ret) {
+        complete(cs, -1, errno_for_gdb());
+        return;
+    }
+    ret = copy_stat_to_user(cs, addr, &buf);
+    complete(cs, ret ? -1 : 0, ret ? -ret : 0);
+}
+
+static void host_stat(CPUState *cs, gdb_syscall_complete_cb complete,
+                      target_ulong fname, target_ulong fname_len,
+                      target_ulong addr)
+{
+    CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
+    struct stat buf;
+    char *name;
+    int ret, err;
+
+    ret = validate_lock_user_string(&name, cs, fname, fname_len);
+    if (ret < 0) {
+        complete(cs, -1, -ret);
+        return;
+    }
+
+    ret = stat(name, &buf);
+    if (ret) {
+        err = errno_for_gdb();
+    } else {
+        ret = copy_stat_to_user(cs, addr, &buf);
+        err = 0;
+        if (ret < 0) {
+            err = -ret;
+            ret = -1;
+        }
+    }
+    complete(cs, ret, err);
+    unlock_user(name, fname, 0);
+}
+
 static void host_remove(CPUState *cs, gdb_syscall_complete_cb complete,
                         target_ulong fname, target_ulong fname_len)
 {
@@ -659,6 +763,39 @@ void semihost_sys_flen(CPUState *cs, gdb_syscall_complete_cb fstat_cb,
     }
 }
 
+void semihost_sys_fstat(CPUState *cs, gdb_syscall_complete_cb complete,
+                        int fd, target_ulong addr)
+{
+    GuestFD *gf = get_guestfd(fd);
+
+    if (!gf) {
+        complete(cs, -1, GDB_EBADF);
+        return;
+    }
+    switch (gf->type) {
+    case GuestFDGDB:
+        gdb_fstat(cs, complete, gf, addr);
+        break;
+    case GuestFDHost:
+        host_fstat(cs, complete, gf, addr);
+        break;
+    case GuestFDStatic:
+    default:
+        g_assert_not_reached();
+    }
+}
+
+void semihost_sys_stat(CPUState *cs, gdb_syscall_complete_cb complete,
+                       target_ulong fname, target_ulong fname_len,
+                       target_ulong addr)
+{
+    if (use_gdb_syscalls()) {
+        gdb_stat(cs, complete, fname, fname_len, addr);
+    } else {
+        host_stat(cs, complete, fname, fname_len, addr);
+    }
+}
+
 void semihost_sys_remove(CPUState *cs, gdb_syscall_complete_cb complete,
                          target_ulong fname, target_ulong fname_len)
 {
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 33/74] semihosting: Create semihost_sys_gettimeofday
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (31 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 32/74] semihosting: Create semihost_sys_{stat,fstat} Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 34/74] gdbstub: Widen gdb_syscall_complete_cb return value Richard Henderson
                   ` (40 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

This syscall will be used by m68k and nios2 semihosting.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/semihosting/syscalls.h |  3 +++
 semihosting/syscalls.c         | 42 ++++++++++++++++++++++++++++++++++
 2 files changed, 45 insertions(+)

diff --git a/include/semihosting/syscalls.h b/include/semihosting/syscalls.h
index ecc97751a9..347200cb9f 100644
--- a/include/semihosting/syscalls.h
+++ b/include/semihosting/syscalls.h
@@ -66,4 +66,7 @@ void semihost_sys_rename(CPUState *cs, gdb_syscall_complete_cb complete,
 void semihost_sys_system(CPUState *cs, gdb_syscall_complete_cb complete,
                          target_ulong cmd, target_ulong cmd_len);
 
+void semihost_sys_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete,
+                               target_ulong tv_addr, target_ulong tz_addr);
+
 #endif /* SEMIHOSTING_SYSCALLS_H */
diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c
index 7bc2640512..269f750d98 100644
--- a/semihosting/syscalls.c
+++ b/semihosting/syscalls.c
@@ -266,6 +266,12 @@ static void gdb_system(CPUState *cs, gdb_syscall_complete_cb complete,
     gdb_do_syscall(complete, "system,%s", cmd, len);
 }
 
+static void gdb_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete,
+                             target_ulong tv_addr, target_ulong tz_addr)
+{
+    gdb_do_syscall(complete, "gettimeofday,%x,%x", tv_addr, tz_addr);
+}
+
 /*
  * Host semihosting syscall implementations.
  */
@@ -517,6 +523,32 @@ static void host_system(CPUState *cs, gdb_syscall_complete_cb complete,
     unlock_user(p, cmd, 0);
 }
 
+static void host_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete,
+                              target_ulong tv_addr, target_ulong tz_addr)
+{
+    CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
+    struct gdb_timeval *p;
+    int64_t rt;
+
+    /* GDB fails on non-null TZ, so be consistent. */
+    if (tz_addr != 0) {
+        complete(cs, -1, GDB_EINVAL);
+        return;
+    }
+
+    p = lock_user(VERIFY_WRITE, tv_addr, sizeof(struct gdb_timeval), 0);
+    if (!p) {
+        complete(cs, -1, GDB_EFAULT);
+        return;
+    }
+
+    /* TODO: Like stat, gdb always produces big-endian results; match it. */
+    rt = g_get_real_time();
+    p->tv_sec = cpu_to_be32(rt / G_USEC_PER_SEC);
+    p->tv_usec = cpu_to_be64(rt % G_USEC_PER_SEC);
+    unlock_user(p, tv_addr, sizeof(struct gdb_timeval));
+}
+
 /*
  * Static file semihosting syscall implementations.
  */
@@ -826,3 +858,13 @@ void semihost_sys_system(CPUState *cs, gdb_syscall_complete_cb complete,
         host_system(cs, complete, cmd, cmd_len);
     }
 }
+
+void semihost_sys_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete,
+                               target_ulong tv_addr, target_ulong tz_addr)
+{
+    if (use_gdb_syscalls()) {
+        gdb_gettimeofday(cs, complete, tv_addr, tz_addr);
+    } else {
+        host_gettimeofday(cs, complete, tv_addr, tz_addr);
+    }
+}
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 34/74] gdbstub: Widen gdb_syscall_complete_cb return value
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (32 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 33/74] semihosting: Create semihost_sys_gettimeofday Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 35/74] semihosting: Fix docs comment for qemu_semihosting_console_inc Richard Henderson
                   ` (39 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

Always pass a uint64_t.  This resolves a FIXME in the
m68k and nios2 semihosting that we've lost data.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/exec/gdbstub.h        |  3 +--
 gdbstub.c                     |  7 ++++---
 semihosting/arm-compat-semi.c |  9 ++++-----
 semihosting/console.c         |  7 +++----
 semihosting/syscalls.c        |  2 +-
 target/m68k/m68k-semi.c       | 10 +++-------
 target/nios2/nios2-semi.c     |  8 +++-----
 7 files changed, 19 insertions(+), 27 deletions(-)

diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index 8e9cdcb1c1..63764a9766 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -77,8 +77,7 @@ struct gdb_timeval {
 #ifdef NEED_CPU_H
 #include "cpu.h"
 
-typedef void (*gdb_syscall_complete_cb)(CPUState *cpu,
-                                        target_ulong ret, target_ulong err);
+typedef void (*gdb_syscall_complete_cb)(CPUState *cpu, uint64_t ret, int err);
 
 /**
  * gdb_do_syscall:
diff --git a/gdbstub.c b/gdbstub.c
index a3ff8702ce..5286253f8a 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1870,11 +1870,12 @@ static void handle_read_all_regs(GArray *params, void *user_ctx)
 static void handle_file_io(GArray *params, void *user_ctx)
 {
     if (params->len >= 1 && gdbserver_state.current_syscall_cb) {
-        target_ulong ret, err;
+        uint64_t ret;
+        int err;
 
-        ret = (target_ulong)get_param(params, 0)->val_ull;
+        ret = get_param(params, 0)->val_ull;
         if (params->len >= 2) {
-            err = (target_ulong)get_param(params, 1)->val_ull;
+            err = get_param(params, 1)->val_ull;
         } else {
             err = 0;
         }
diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index a7520d6f41..3ca8b6455c 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -217,7 +217,7 @@ static inline uint32_t get_swi_errno(CPUState *cs)
 #endif
 }
 
-static void common_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
+static void common_semi_cb(CPUState *cs, uint64_t ret, int err)
 {
     if (err) {
 #ifdef CONFIG_USER_ONLY
@@ -234,7 +234,7 @@ static void common_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
  * SYS_READ and SYS_WRITE always return the number of bytes not read/written.
  * There is no error condition, other than returning the original length.
  */
-static void common_semi_rw_cb(CPUState *cs, target_ulong ret, target_ulong err)
+static void common_semi_rw_cb(CPUState *cs, uint64_t ret, int err)
 {
     /* Recover the original length from the third argument. */
     CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
@@ -251,8 +251,7 @@ static void common_semi_rw_cb(CPUState *cs, target_ulong ret, target_ulong err)
 /*
  * SYS_SEEK returns 0 on success, not the resulting offset.
  */
-static void common_semi_seek_cb(CPUState *cs, target_ulong ret,
-                                target_ulong err)
+static void common_semi_seek_cb(CPUState *cs, uint64_t ret, int err)
 {
     if (!err) {
         ret = 0;
@@ -273,7 +272,7 @@ static target_ulong common_semi_flen_buf(CPUState *cs)
 }
 
 static void
-common_semi_flen_fstat_cb(CPUState *cs, target_ulong ret, target_ulong err)
+common_semi_flen_fstat_cb(CPUState *cs, uint64_t ret, int err)
 {
     if (!err) {
         /* The size is always stored in big-endian order, extract the value. */
diff --git a/semihosting/console.c b/semihosting/console.c
index ef6958d844..3dd0ac60e2 100644
--- a/semihosting/console.c
+++ b/semihosting/console.c
@@ -64,11 +64,10 @@ static GString *copy_user_string(CPUArchState *env, target_ulong addr)
     return s;
 }
 
-static void semihosting_cb(CPUState *cs, target_ulong ret, target_ulong err)
+static void semihosting_cb(CPUState *cs, uint64_t ret, int err)
 {
-    if (ret == (target_ulong) -1) {
-        qemu_log("%s: gdb console output failed ("TARGET_FMT_ld")",
-                 __func__, err);
+    if (err) {
+        qemu_log("%s: gdb console output failed (%d)", __func__, err);
     }
 }
 
diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c
index 269f750d98..4c934654cd 100644
--- a/semihosting/syscalls.c
+++ b/semihosting/syscalls.c
@@ -145,7 +145,7 @@ static int copy_stat_to_user(CPUState *cs, target_ulong addr,
 
 static gdb_syscall_complete_cb gdb_open_complete;
 
-static void gdb_open_cb(CPUState *cs, target_ulong ret, target_ulong err)
+static void gdb_open_cb(CPUState *cs, uint64_t ret, int err)
 {
     if (!err) {
         int guestfd = alloc_guestfd();
diff --git a/target/m68k/m68k-semi.c b/target/m68k/m68k-semi.c
index da0186f3ef..94deebf09e 100644
--- a/target/m68k/m68k-semi.c
+++ b/target/m68k/m68k-semi.c
@@ -93,7 +93,7 @@ static void translate_stat(CPUM68KState *env, target_ulong addr, struct stat *s)
     unlock_user(p, addr, sizeof(struct gdb_stat));
 }
 
-static void m68k_semi_return_u32(CPUM68KState *env, uint32_t ret, uint32_t err)
+static void m68k_semi_return_u32(CPUM68KState *env, uint32_t ret, int err)
 {
     target_ulong args = env->dregs[1];
     if (put_user_u32(ret, args) ||
@@ -108,7 +108,7 @@ static void m68k_semi_return_u32(CPUM68KState *env, uint32_t ret, uint32_t err)
     }
 }
 
-static void m68k_semi_return_u64(CPUM68KState *env, uint64_t ret, uint32_t err)
+static void m68k_semi_return_u64(CPUM68KState *env, uint64_t ret, int err)
 {
     target_ulong args = env->dregs[1];
     if (put_user_u32(ret >> 32, args) ||
@@ -122,16 +122,12 @@ static void m68k_semi_return_u64(CPUM68KState *env, uint64_t ret, uint32_t err)
 
 static int m68k_semi_is_fseek;
 
-static void m68k_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
+static void m68k_semi_cb(CPUState *cs, uint64_t ret, int err)
 {
     M68kCPU *cpu = M68K_CPU(cs);
     CPUM68KState *env = &cpu->env;
 
     if (m68k_semi_is_fseek) {
-        /*
-         * FIXME: We've already lost the high bits of the fseek
-         * return value.
-         */
         m68k_semi_return_u64(env, ret, err);
         m68k_semi_is_fseek = 0;
     } else {
diff --git a/target/nios2/nios2-semi.c b/target/nios2/nios2-semi.c
index 3e504a6c5f..4d02789d26 100644
--- a/target/nios2/nios2-semi.c
+++ b/target/nios2/nios2-semi.c
@@ -108,8 +108,7 @@ static bool translate_stat(CPUNios2State *env, target_ulong addr,
     return true;
 }
 
-static void nios2_semi_return_u32(CPUNios2State *env, uint32_t ret,
-                                  uint32_t err)
+static void nios2_semi_return_u32(CPUNios2State *env, uint32_t ret, int err)
 {
     target_ulong args = env->regs[R_ARG1];
     if (put_user_u32(ret, args) ||
@@ -124,8 +123,7 @@ static void nios2_semi_return_u32(CPUNios2State *env, uint32_t ret,
     }
 }
 
-static void nios2_semi_return_u64(CPUNios2State *env, uint64_t ret,
-                                  uint32_t err)
+static void nios2_semi_return_u64(CPUNios2State *env, uint64_t ret, int err)
 {
     target_ulong args = env->regs[R_ARG1];
     if (put_user_u32(ret >> 32, args) ||
@@ -139,7 +137,7 @@ static void nios2_semi_return_u64(CPUNios2State *env, uint64_t ret,
 
 static int nios2_semi_is_lseek;
 
-static void nios2_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
+static void nios2_semi_cb(CPUState *cs, uint64_t ret, int err)
 {
     Nios2CPU *cpu = NIOS2_CPU(cs);
     CPUNios2State *env = &cpu->env;
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 35/74] semihosting: Fix docs comment for qemu_semihosting_console_inc
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (33 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 34/74] gdbstub: Widen gdb_syscall_complete_cb return value Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 36/74] semihosting: Pass CPUState to qemu_semihosting_console_inc Richard Henderson
                   ` (38 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

The implementation of qemu_semihosting_console_inc does not
defer to gdbstub, but only reads from the fifo in console.c.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/semihosting/console.h | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/include/semihosting/console.h b/include/semihosting/console.h
index 0238f540f4..4f6217bf10 100644
--- a/include/semihosting/console.h
+++ b/include/semihosting/console.h
@@ -41,11 +41,10 @@ void qemu_semihosting_console_outc(CPUArchState *env, target_ulong c);
  * qemu_semihosting_console_inc:
  * @env: CPUArchState
  *
- * Receive single character from debug console. This may be the remote
- * gdb session if a softmmu guest is currently being debugged. As this
- * call may block if no data is available we suspend the CPU and will
- * re-execute the instruction when data is there. Therefore two
- * conditions must be met:
+ * Receive single character from debug console.  As this call may block
+ * if no data is available we suspend the CPU and will re-execute the
+ * instruction when data is there. Therefore two conditions must be met:
+ *
  *   - CPUState is synchronized before calling this function
  *   - pc is only updated once the character is successfully returned
  *
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 36/74] semihosting: Pass CPUState to qemu_semihosting_console_inc
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (34 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 35/74] semihosting: Fix docs comment for qemu_semihosting_console_inc Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 37/74] semihosting: Expand qemu_semihosting_console_inc to read Richard Henderson
                   ` (37 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

We don't need CPUArchState, and we do want the CPUState of the
thread performing the operation -- use this instead of current_cpu.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/semihosting/console.h |  4 ++--
 linux-user/semihost.c         |  2 +-
 semihosting/arm-compat-semi.c |  2 +-
 semihosting/console.c         | 12 ++++++------
 4 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/include/semihosting/console.h b/include/semihosting/console.h
index 4f6217bf10..afc961057c 100644
--- a/include/semihosting/console.h
+++ b/include/semihosting/console.h
@@ -39,7 +39,7 @@ void qemu_semihosting_console_outc(CPUArchState *env, target_ulong c);
 
 /**
  * qemu_semihosting_console_inc:
- * @env: CPUArchState
+ * @: CPUState
  *
  * Receive single character from debug console.  As this call may block
  * if no data is available we suspend the CPU and will re-execute the
@@ -50,7 +50,7 @@ void qemu_semihosting_console_outc(CPUArchState *env, target_ulong c);
  *
  * Returns: character read OR cpu_loop_exit!
  */
-target_ulong qemu_semihosting_console_inc(CPUArchState *env);
+target_ulong qemu_semihosting_console_inc(CPUState *cs);
 
 /**
  * qemu_semihosting_log_out:
diff --git a/linux-user/semihost.c b/linux-user/semihost.c
index 17f074ac56..f14c6ae21d 100644
--- a/linux-user/semihost.c
+++ b/linux-user/semihost.c
@@ -56,7 +56,7 @@ void qemu_semihosting_console_outc(CPUArchState *env, target_ulong addr)
  * program is expecting more normal behaviour. This is slow but
  * nothing using semihosting console reading is expecting to be fast.
  */
-target_ulong qemu_semihosting_console_inc(CPUArchState *env)
+target_ulong qemu_semihosting_console_inc(CPUState *cs)
 {
     uint8_t c;
     struct termios old_tio, new_tio;
diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index 3ca8b6455c..c4cf33fe0e 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -418,7 +418,7 @@ void do_common_semihosting(CPUState *cs)
         break;
 
     case TARGET_SYS_READC:
-        ret = qemu_semihosting_console_inc(env);
+        ret = qemu_semihosting_console_inc(cs);
         common_semi_set_ret(cs, ret);
         break;
 
diff --git a/semihosting/console.c b/semihosting/console.c
index 3dd0ac60e2..7b896fe43b 100644
--- a/semihosting/console.c
+++ b/semihosting/console.c
@@ -144,17 +144,17 @@ static void console_read(void *opaque, const uint8_t *buf, int size)
     c->sleeping_cpus = NULL;
 }
 
-target_ulong qemu_semihosting_console_inc(CPUArchState *env)
+target_ulong qemu_semihosting_console_inc(CPUState *cs)
 {
     uint8_t ch;
     SemihostingConsole *c = &console;
+
     g_assert(qemu_mutex_iothread_locked());
-    g_assert(current_cpu);
     if (fifo8_is_empty(&c->fifo)) {
-        c->sleeping_cpus = g_slist_prepend(c->sleeping_cpus, current_cpu);
-        current_cpu->halted = 1;
-        current_cpu->exception_index = EXCP_HALTED;
-        cpu_loop_exit(current_cpu);
+        c->sleeping_cpus = g_slist_prepend(c->sleeping_cpus, cs);
+        cs->halted = 1;
+        cs->exception_index = EXCP_HALTED;
+        cpu_loop_exit(cs);
         /* never returns */
     }
     ch = fifo8_pop(&c->fifo);
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 37/74] semihosting: Expand qemu_semihosting_console_inc to read
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (35 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 36/74] semihosting: Pass CPUState to qemu_semihosting_console_inc Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 38/74] semihosting: Cleanup chardev init Richard Henderson
                   ` (36 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

Allow more than one character to be read at one time.
Will be used by m68k and nios2 semihosting for stdio.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/semihosting/console.h | 14 ++++++++------
 linux-user/semihost.c         | 10 ++++++----
 semihosting/arm-compat-semi.c | 11 +++++++++--
 semihosting/console.c         | 16 ++++++++++++----
 4 files changed, 35 insertions(+), 16 deletions(-)

diff --git a/include/semihosting/console.h b/include/semihosting/console.h
index afc961057c..39dbf1b062 100644
--- a/include/semihosting/console.h
+++ b/include/semihosting/console.h
@@ -38,19 +38,21 @@ int qemu_semihosting_console_outs(CPUArchState *env, target_ulong s);
 void qemu_semihosting_console_outc(CPUArchState *env, target_ulong c);
 
 /**
- * qemu_semihosting_console_inc:
- * @: CPUState
+ * qemu_semihosting_console_read:
+ * @cs: CPUState
+ * @buf: host buffer
+ * @len: buffer size
  *
- * Receive single character from debug console.  As this call may block
- * if no data is available we suspend the CPU and will re-execute the
+ * Receive at least one character from debug console.  As this call may
+ * block if no data is available we suspend the CPU and will re-execute the
  * instruction when data is there. Therefore two conditions must be met:
  *
  *   - CPUState is synchronized before calling this function
  *   - pc is only updated once the character is successfully returned
  *
- * Returns: character read OR cpu_loop_exit!
+ * Returns: number of characters read, OR cpu_loop_exit!
  */
-target_ulong qemu_semihosting_console_inc(CPUState *cs);
+int qemu_semihosting_console_read(CPUState *cs, void *buf, int len);
 
 /**
  * qemu_semihosting_log_out:
diff --git a/linux-user/semihost.c b/linux-user/semihost.c
index f14c6ae21d..2029fb674c 100644
--- a/linux-user/semihost.c
+++ b/linux-user/semihost.c
@@ -56,21 +56,23 @@ void qemu_semihosting_console_outc(CPUArchState *env, target_ulong addr)
  * program is expecting more normal behaviour. This is slow but
  * nothing using semihosting console reading is expecting to be fast.
  */
-target_ulong qemu_semihosting_console_inc(CPUState *cs)
+int qemu_semihosting_console_read(CPUState *cs, void *buf, int len)
 {
-    uint8_t c;
+    int ret;
     struct termios old_tio, new_tio;
 
     /* Disable line-buffering and echo */
     tcgetattr(STDIN_FILENO, &old_tio);
     new_tio = old_tio;
     new_tio.c_lflag &= (~ICANON & ~ECHO);
+    new_tio.c_cc[VMIN] = 1;
+    new_tio.c_cc[VTIME] = 0;
     tcsetattr(STDIN_FILENO, TCSANOW, &new_tio);
 
-    c = getchar();
+    ret = fread(buf, 1, len, stdin);
 
     /* restore config */
     tcsetattr(STDIN_FILENO, TCSANOW, &old_tio);
 
-    return (target_ulong) c;
+    return ret;
 }
diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index c4cf33fe0e..d60f7ed6a4 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -418,8 +418,15 @@ void do_common_semihosting(CPUState *cs)
         break;
 
     case TARGET_SYS_READC:
-        ret = qemu_semihosting_console_inc(cs);
-        common_semi_set_ret(cs, ret);
+        {
+            uint8_t ch;
+            int ret = qemu_semihosting_console_read(cs, &ch, 1);
+            if (ret == 1) {
+                common_semi_cb(cs, ch, 0);
+            } else {
+                common_semi_cb(cs, -1, EIO);
+            }
+        }
         break;
 
     case TARGET_SYS_ISERROR:
diff --git a/semihosting/console.c b/semihosting/console.c
index 7b896fe43b..df618a28a4 100644
--- a/semihosting/console.c
+++ b/semihosting/console.c
@@ -144,12 +144,14 @@ static void console_read(void *opaque, const uint8_t *buf, int size)
     c->sleeping_cpus = NULL;
 }
 
-target_ulong qemu_semihosting_console_inc(CPUState *cs)
+int qemu_semihosting_console_read(CPUState *cs, void *buf, int len)
 {
-    uint8_t ch;
     SemihostingConsole *c = &console;
+    int ret = 0;
 
     g_assert(qemu_mutex_iothread_locked());
+
+    /* Block if the fifo is completely empty. */
     if (fifo8_is_empty(&c->fifo)) {
         c->sleeping_cpus = g_slist_prepend(c->sleeping_cpus, cs);
         cs->halted = 1;
@@ -157,8 +159,14 @@ target_ulong qemu_semihosting_console_inc(CPUState *cs)
         cpu_loop_exit(cs);
         /* never returns */
     }
-    ch = fifo8_pop(&c->fifo);
-    return (target_ulong) ch;
+
+    /* Read until buffer full or fifo exhausted. */
+    do {
+        *(char *)(buf + ret) = fifo8_pop(&c->fifo);
+        ret++;
+    } while (ret < len && !fifo8_is_empty(&c->fifo));
+
+    return ret;
 }
 
 void qemu_semihosting_console_init(void)
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 38/74] semihosting: Cleanup chardev init
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (36 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 37/74] semihosting: Expand qemu_semihosting_console_inc to read Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 39/74] semihosting: Create qemu_semihosting_console_write Richard Henderson
                   ` (35 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

Rename qemu_semihosting_connect_chardevs to
qemu_semihosting_chardev_init; pass the result
directly to qemu_semihosting_console_init.

Store the chardev in SemihostingConsole instead
of SemihostingConfig, which lets us drop
semihosting_get_chardev.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/semihosting/semihost.h | 13 ++-----------
 semihosting/config.c           | 17 +++++++----------
 semihosting/console.c          | 31 +++++++++++++++----------------
 softmmu/vl.c                   |  3 +--
 stubs/semihost.c               |  6 +-----
 5 files changed, 26 insertions(+), 44 deletions(-)

diff --git a/include/semihosting/semihost.h b/include/semihosting/semihost.h
index 0c55ade3ac..5b36a76f08 100644
--- a/include/semihosting/semihost.h
+++ b/include/semihosting/semihost.h
@@ -51,14 +51,6 @@ static inline const char *semihosting_get_cmdline(void)
 {
     return NULL;
 }
-
-static inline Chardev *semihosting_get_chardev(void)
-{
-    return NULL;
-}
-static inline void qemu_semihosting_console_init(void)
-{
-}
 #else /* !CONFIG_USER_ONLY */
 bool semihosting_enabled(void);
 SemihostingTarget semihosting_get_target(void);
@@ -66,12 +58,11 @@ const char *semihosting_get_arg(int i);
 int semihosting_get_argc(void);
 const char *semihosting_get_cmdline(void);
 void semihosting_arg_fallback(const char *file, const char *cmd);
-Chardev *semihosting_get_chardev(void);
 /* for vl.c hooks */
 void qemu_semihosting_enable(void);
 int qemu_semihosting_config_options(const char *opt);
-void qemu_semihosting_connect_chardevs(void);
-void qemu_semihosting_console_init(void);
+void qemu_semihosting_chardev_init(void);
+void qemu_semihosting_console_init(Chardev *);
 #endif /* CONFIG_USER_ONLY */
 
 #endif /* SEMIHOST_H */
diff --git a/semihosting/config.c b/semihosting/config.c
index 50d82108e6..4bca769fad 100644
--- a/semihosting/config.c
+++ b/semihosting/config.c
@@ -50,7 +50,6 @@ QemuOptsList qemu_semihosting_config_opts = {
 typedef struct SemihostingConfig {
     bool enabled;
     SemihostingTarget target;
-    Chardev *chardev;
     char **argv;
     int argc;
     const char *cmdline; /* concatenated argv */
@@ -121,11 +120,6 @@ void semihosting_arg_fallback(const char *file, const char *cmd)
     }
 }
 
-Chardev *semihosting_get_chardev(void)
-{
-    return semihosting.chardev;
-}
-
 void qemu_semihosting_enable(void)
 {
     semihosting.enabled = true;
@@ -171,16 +165,19 @@ int qemu_semihosting_config_options(const char *optarg)
     return 0;
 }
 
-void qemu_semihosting_connect_chardevs(void)
+/* We had to defer this until chardevs were created */
+void qemu_semihosting_chardev_init(void)
 {
-    /* We had to defer this until chardevs were created */
+    Chardev *chr = NULL;
+
     if (semihost_chardev) {
-        Chardev *chr = qemu_chr_find(semihost_chardev);
+        chr = qemu_chr_find(semihost_chardev);
         if (chr == NULL) {
             error_report("semihosting chardev '%s' not found",
                          semihost_chardev);
             exit(1);
         }
-        semihosting.chardev = chr;
     }
+
+    qemu_semihosting_console_init(chr);
 }
diff --git a/semihosting/console.c b/semihosting/console.c
index df618a28a4..4088192842 100644
--- a/semihosting/console.c
+++ b/semihosting/console.c
@@ -27,11 +27,21 @@
 #include "qapi/error.h"
 #include "qemu/fifo8.h"
 
+/* Access to this structure is protected by the BQL */
+typedef struct SemihostingConsole {
+    CharBackend         backend;
+    Chardev             *chr;
+    GSList              *sleeping_cpus;
+    bool                got;
+    Fifo8               fifo;
+} SemihostingConsole;
+
+static SemihostingConsole console;
+
 int qemu_semihosting_log_out(const char *s, int len)
 {
-    Chardev *chardev = semihosting_get_chardev();
-    if (chardev) {
-        return qemu_chr_write_all(chardev, (uint8_t *) s, len);
+    if (console.chr) {
+        return qemu_chr_write_all(console.chr, (uint8_t *) s, len);
     } else {
         return write(STDERR_FILENO, s, len);
     }
@@ -106,16 +116,6 @@ void qemu_semihosting_console_outc(CPUArchState *env, target_ulong addr)
 
 #define FIFO_SIZE   1024
 
-/* Access to this structure is protected by the BQL */
-typedef struct SemihostingConsole {
-    CharBackend         backend;
-    GSList              *sleeping_cpus;
-    bool                got;
-    Fifo8               fifo;
-} SemihostingConsole;
-
-static SemihostingConsole console;
-
 static int console_can_read(void *opaque)
 {
     SemihostingConsole *c = opaque;
@@ -169,10 +169,9 @@ int qemu_semihosting_console_read(CPUState *cs, void *buf, int len)
     return ret;
 }
 
-void qemu_semihosting_console_init(void)
+void qemu_semihosting_console_init(Chardev *chr)
 {
-    Chardev *chr = semihosting_get_chardev();
-
+    console.chr = chr;
     if  (chr) {
         fifo8_create(&console.fifo, FIFO_SIZE);
         qemu_chr_fe_init(&console.backend, chr, &error_abort);
diff --git a/softmmu/vl.c b/softmmu/vl.c
index c2919579fd..009b660588 100644
--- a/softmmu/vl.c
+++ b/softmmu/vl.c
@@ -2019,8 +2019,7 @@ static void qemu_create_late_backends(void)
         exit(1);
 
     /* now chardevs have been created we may have semihosting to connect */
-    qemu_semihosting_connect_chardevs();
-    qemu_semihosting_console_init();
+    qemu_semihosting_chardev_init();
 }
 
 static bool have_custom_ram_size(void)
diff --git a/stubs/semihost.c b/stubs/semihost.c
index 4bf2cf71b9..f486651afb 100644
--- a/stubs/semihost.c
+++ b/stubs/semihost.c
@@ -65,10 +65,6 @@ void semihosting_arg_fallback(const char *file, const char *cmd)
 {
 }
 
-void qemu_semihosting_connect_chardevs(void)
-{
-}
-
-void qemu_semihosting_console_init(void)
+void qemu_semihosting_chardev_init(void)
 {
 }
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 39/74] semihosting: Create qemu_semihosting_console_write
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (37 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 38/74] semihosting: Cleanup chardev init Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 40/74] semihosting: Add GuestFDConsole Richard Henderson
                   ` (34 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

Will replace qemu_semihosting_console_{outs,outc},
but we need more plumbing first.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/semihosting/console.h | 12 ++++++++++++
 linux-user/semihost.c         |  5 +++++
 semihosting/console.c         |  9 +++++++++
 3 files changed, 26 insertions(+)

diff --git a/include/semihosting/console.h b/include/semihosting/console.h
index 39dbf1b062..6994f23c82 100644
--- a/include/semihosting/console.h
+++ b/include/semihosting/console.h
@@ -54,6 +54,18 @@ void qemu_semihosting_console_outc(CPUArchState *env, target_ulong c);
  */
 int qemu_semihosting_console_read(CPUState *cs, void *buf, int len);
 
+/**
+ * qemu_semihosting_console_write:
+ * @buf: host buffer
+ * @len: buffer size
+ *
+ * Write len bytes from buf to the debug console.
+ *
+ * Returns: number of bytes written -- this should only ever be short
+ * on some sort of i/o error.
+ */
+int qemu_semihosting_console_write(void *buf, int len);
+
 /**
  * qemu_semihosting_log_out:
  * @s: pointer to string
diff --git a/linux-user/semihost.c b/linux-user/semihost.c
index 2029fb674c..871edf993a 100644
--- a/linux-user/semihost.c
+++ b/linux-user/semihost.c
@@ -76,3 +76,8 @@ int qemu_semihosting_console_read(CPUState *cs, void *buf, int len)
 
     return ret;
 }
+
+int qemu_semihosting_console_write(void *buf, int len)
+{
+    return fwrite(buf, 1, len, stderr);
+}
diff --git a/semihosting/console.c b/semihosting/console.c
index 4088192842..b6a342744d 100644
--- a/semihosting/console.c
+++ b/semihosting/console.c
@@ -169,6 +169,15 @@ int qemu_semihosting_console_read(CPUState *cs, void *buf, int len)
     return ret;
 }
 
+int qemu_semihosting_console_write(void *buf, int len)
+{
+    if (console.chr) {
+        return qemu_chr_write_all(console.chr, (uint8_t *)buf, len);
+    } else {
+        return fwrite(buf, 1, len, stderr);
+    }
+}
+
 void qemu_semihosting_console_init(Chardev *chr)
 {
     console.chr = chr;
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 40/74] semihosting: Add GuestFDConsole
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (38 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 39/74] semihosting: Create qemu_semihosting_console_write Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 41/74] semihosting: Create qemu_semihosting_guestfd_init Richard Henderson
                   ` (33 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

Add a GuestFDType for connecting to the semihosting console.
Hook up to read, write, isatty, and fstat syscalls.

Note that the arm-specific syscall flen cannot be applied
to the console, because the console is not a descriptor
exposed to the guest.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/semihosting/guestfd.h |  7 ++--
 semihosting/syscalls.c        | 68 +++++++++++++++++++++++++++++++++++
 2 files changed, 72 insertions(+), 3 deletions(-)

diff --git a/include/semihosting/guestfd.h b/include/semihosting/guestfd.h
index 5aa2722cb2..5c3e7cd538 100644
--- a/include/semihosting/guestfd.h
+++ b/include/semihosting/guestfd.h
@@ -13,9 +13,10 @@
 
 typedef enum GuestFDType {
     GuestFDUnused = 0,
-    GuestFDHost = 1,
-    GuestFDGDB = 2,
-    GuestFDStatic = 3,
+    GuestFDHost,
+    GuestFDGDB,
+    GuestFDStatic,
+    GuestFDConsole,
 } GuestFDType;
 
 /*
diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c
index 4c934654cd..aa4ee47649 100644
--- a/semihosting/syscalls.c
+++ b/semihosting/syscalls.c
@@ -10,6 +10,7 @@
 #include "exec/gdbstub.h"
 #include "semihosting/guestfd.h"
 #include "semihosting/syscalls.h"
+#include "semihosting/console.h"
 #ifdef CONFIG_USER_ONLY
 #include "qemu.h"
 #else
@@ -607,6 +608,56 @@ static void staticfile_flen(CPUState *cs, gdb_syscall_complete_cb complete,
     complete(cs, gf->staticfile.len, 0);
 }
 
+/*
+ * Console semihosting syscall implementations.
+ */
+
+static void console_read(CPUState *cs, gdb_syscall_complete_cb complete,
+                         GuestFD *gf, target_ulong buf, target_ulong len)
+{
+    CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
+    char *ptr;
+    int ret;
+
+    ptr = lock_user(VERIFY_WRITE, buf, len, 0);
+    if (!ptr) {
+        complete(cs, -1, EFAULT);
+        return;
+    }
+    ret = qemu_semihosting_console_read(cs, ptr, len);
+    complete(cs, ret, 0);
+    unlock_user(ptr, buf, ret);
+}
+
+static void console_write(CPUState *cs, gdb_syscall_complete_cb complete,
+                          GuestFD *gf, target_ulong buf, target_ulong len)
+{
+    CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
+    char *ptr = lock_user(VERIFY_READ, buf, len, 1);
+    int ret;
+
+    if (!ptr) {
+        complete(cs, -1, EFAULT);
+        return;
+    }
+    ret = qemu_semihosting_console_write(ptr, len);
+    complete(cs, ret ? ret : -1, ret ? 0 : EIO);
+    unlock_user(ptr, buf, ret);
+}
+
+static void console_fstat(CPUState *cs, gdb_syscall_complete_cb complete,
+                          GuestFD *gf, target_ulong addr)
+{
+    static const struct stat tty_buf = {
+        .st_mode = 020666,  /* S_IFCHR, ugo+rw */
+        .st_rdev = 5,       /* makedev(5, 0) -- linux /dev/tty */
+    };
+    int ret;
+
+    ret = copy_stat_to_user(cs, addr, &tty_buf);
+    complete(cs, ret ? -1 : 0, ret ? -ret : 0);
+}
+
 /*
  * Syscall entry points.
  */
@@ -638,6 +689,7 @@ void semihost_sys_close(CPUState *cs, gdb_syscall_complete_cb complete, int fd)
         host_close(cs, complete, gf);
         break;
     case GuestFDStatic:
+    case GuestFDConsole:
         complete(cs, 0, 0);
         break;
     default:
@@ -667,6 +719,9 @@ void semihost_sys_read_gf(CPUState *cs, gdb_syscall_complete_cb complete,
     case GuestFDStatic:
         staticfile_read(cs, complete, gf, buf, len);
         break;
+    case GuestFDConsole:
+        console_read(cs, complete, gf, buf, len);
+        break;
     default:
         g_assert_not_reached();
     }
@@ -702,6 +757,9 @@ void semihost_sys_write_gf(CPUState *cs, gdb_syscall_complete_cb complete,
     case GuestFDHost:
         host_write(cs, complete, gf, buf, len);
         break;
+    case GuestFDConsole:
+        console_write(cs, complete, gf, buf, len);
+        break;
     case GuestFDStatic:
         /* Static files are never open for writing: EBADF. */
         complete(cs, -1, GDB_EBADF);
@@ -742,6 +800,9 @@ void semihost_sys_lseek(CPUState *cs, gdb_syscall_complete_cb complete,
     case GuestFDStatic:
         staticfile_lseek(cs, complete, gf, off, gdb_whence);
         break;
+    case GuestFDConsole:
+        complete(cs, -1, ESPIPE);
+        break;
     default:
         g_assert_not_reached();
     }
@@ -765,6 +826,9 @@ void semihost_sys_isatty(CPUState *cs, gdb_syscall_complete_cb complete, int fd)
     case GuestFDStatic:
         complete(cs, 0, GDB_ENOTTY);
         break;
+    case GuestFDConsole:
+        complete(cs, 1, 0);
+        break;
     default:
         g_assert_not_reached();
     }
@@ -790,6 +854,7 @@ void semihost_sys_flen(CPUState *cs, gdb_syscall_complete_cb fstat_cb,
     case GuestFDStatic:
         staticfile_flen(cs, flen_cb, gf);
         break;
+    case GuestFDConsole:
     default:
         g_assert_not_reached();
     }
@@ -811,6 +876,9 @@ void semihost_sys_fstat(CPUState *cs, gdb_syscall_complete_cb complete,
     case GuestFDHost:
         host_fstat(cs, complete, gf, addr);
         break;
+    case GuestFDConsole:
+        console_fstat(cs, complete, gf, addr);
+        break;
     case GuestFDStatic:
     default:
         g_assert_not_reached();
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 41/74] semihosting: Create qemu_semihosting_guestfd_init
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (39 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 40/74] semihosting: Add GuestFDConsole Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 42/74] semihosting: Use console_in_gf for SYS_READC Richard Henderson
                   ` (32 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

For arm-compat, initialize console_{in,out}_gf;
otherwise, initialize stdio file descriptors.

This will go some way to cleaning up arm-compat, and
will allow other semihosting to use normal stdio.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/semihosting/guestfd.h  |  7 +++++
 include/semihosting/semihost.h |  1 +
 linux-user/main.c              |  9 ++++++
 semihosting/console.c          |  2 ++
 semihosting/guestfd.c          | 52 +++++++++++++++++++++++++++-------
 5 files changed, 61 insertions(+), 10 deletions(-)

diff --git a/include/semihosting/guestfd.h b/include/semihosting/guestfd.h
index 5c3e7cd538..73d8235222 100644
--- a/include/semihosting/guestfd.h
+++ b/include/semihosting/guestfd.h
@@ -35,6 +35,13 @@ typedef struct GuestFD {
     };
 } GuestFD;
 
+/*
+ * For ARM semihosting, we have a separate structure for routing
+ * data for the console which is outside the guest fd address space.
+ */
+extern GuestFD console_in_gf;
+extern GuestFD console_out_gf;
+
 int alloc_guestfd(void);
 void dealloc_guestfd(int guestfd);
 GuestFD *get_guestfd(int guestfd);
diff --git a/include/semihosting/semihost.h b/include/semihosting/semihost.h
index 5b36a76f08..93a3c21b44 100644
--- a/include/semihosting/semihost.h
+++ b/include/semihosting/semihost.h
@@ -64,5 +64,6 @@ int qemu_semihosting_config_options(const char *opt);
 void qemu_semihosting_chardev_init(void);
 void qemu_semihosting_console_init(Chardev *);
 #endif /* CONFIG_USER_ONLY */
+void qemu_semihosting_guestfd_init(void);
 
 #endif /* SEMIHOST_H */
diff --git a/linux-user/main.c b/linux-user/main.c
index 7ca48664e4..7faf390df9 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -54,6 +54,10 @@
 #include "loader.h"
 #include "user-mmap.h"
 
+#ifdef CONFIG_SEMIHOSTING
+#include "semihosting/semihost.h"
+#endif
+
 #ifndef AT_FLAGS_PRESERVE_ARGV0
 #define AT_FLAGS_PRESERVE_ARGV0_BIT 0
 #define AT_FLAGS_PRESERVE_ARGV0 (1 << AT_FLAGS_PRESERVE_ARGV0_BIT)
@@ -906,6 +910,11 @@ int main(int argc, char **argv, char **envp)
         }
         gdb_handlesig(cpu, 0);
     }
+
+#ifdef CONFIG_SEMIHOSTING
+    qemu_semihosting_guestfd_init();
+#endif
+
     cpu_loop(env);
     /* never exits */
     return 0;
diff --git a/semihosting/console.c b/semihosting/console.c
index b6a342744d..677ec2b176 100644
--- a/semihosting/console.c
+++ b/semihosting/console.c
@@ -190,4 +190,6 @@ void qemu_semihosting_console_init(Chardev *chr)
                                  NULL, NULL, &console,
                                  NULL, true);
     }
+
+    qemu_semihosting_guestfd_init();
 }
diff --git a/semihosting/guestfd.c b/semihosting/guestfd.c
index e3122ebba9..b05c52f26f 100644
--- a/semihosting/guestfd.c
+++ b/semihosting/guestfd.c
@@ -10,15 +10,56 @@
 
 #include "qemu/osdep.h"
 #include "exec/gdbstub.h"
+#include "semihosting/semihost.h"
 #include "semihosting/guestfd.h"
 #ifdef CONFIG_USER_ONLY
 #include "qemu.h"
 #else
 #include "semihosting/softmmu-uaccess.h"
+#include CONFIG_DEVICES
 #endif
 
 static GArray *guestfd_array;
 
+#ifdef CONFIG_ARM_COMPATIBLE_SEMIHOSTING
+GuestFD console_in_gf;
+GuestFD console_out_gf;
+#endif
+
+void qemu_semihosting_guestfd_init(void)
+{
+    /* New entries zero-initialized, i.e. type GuestFDUnused */
+    guestfd_array = g_array_new(FALSE, TRUE, sizeof(GuestFD));
+
+#ifdef CONFIG_ARM_COMPATIBLE_SEMIHOSTING
+    /* For ARM-compat, the console is in a separate namespace. */
+    if (use_gdb_syscalls()) {
+        console_in_gf.type = GuestFDGDB;
+        console_in_gf.hostfd = 0;
+        console_out_gf.type = GuestFDGDB;
+        console_out_gf.hostfd = 2;
+    } else {
+        console_in_gf.type = GuestFDConsole;
+        console_out_gf.type = GuestFDConsole;
+    }
+#else
+    /* Otherwise, the stdio file descriptors apply. */
+    guestfd_array = g_array_set_size(guestfd_array, 3);
+#ifndef CONFIG_USER_ONLY
+    if (!use_gdb_syscalls()) {
+        GuestFD *gf = &g_array_index(guestfd_array, GuestFD, 0);
+        gf[0].type = GuestFDConsole;
+        gf[1].type = GuestFDConsole;
+        gf[2].type = GuestFDConsole;
+        return;
+    }
+#endif
+    associate_guestfd(0, 0);
+    associate_guestfd(1, 1);
+    associate_guestfd(2, 2);
+#endif
+}
+
 /*
  * Allocate a new guest file descriptor and return it; if we
  * couldn't allocate a new fd then return -1.
@@ -30,11 +71,6 @@ int alloc_guestfd(void)
 {
     guint i;
 
-    if (!guestfd_array) {
-        /* New entries zero-initialized, i.e. type GuestFDUnused */
-        guestfd_array = g_array_new(FALSE, TRUE, sizeof(GuestFD));
-    }
-
     /* SYS_OPEN should return nonzero handle on success. Start guestfd from 1 */
     for (i = 1; i < guestfd_array->len; i++) {
         GuestFD *gf = &g_array_index(guestfd_array, GuestFD, i);
@@ -61,11 +97,7 @@ static void do_dealloc_guestfd(GuestFD *gf)
  */
 static GuestFD *do_get_guestfd(int guestfd)
 {
-    if (!guestfd_array) {
-        return NULL;
-    }
-
-    if (guestfd <= 0 || guestfd >= guestfd_array->len) {
+    if (guestfd < 0 || guestfd >= guestfd_array->len) {
         return NULL;
     }
 
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 42/74] semihosting: Use console_in_gf for SYS_READC
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (40 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 41/74] semihosting: Create qemu_semihosting_guestfd_init Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 43/74] semihosting: Use console_out_gf for SYS_WRITEC Richard Henderson
                   ` (31 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 semihosting/arm-compat-semi.c | 27 ++++++++++++++++++---------
 1 file changed, 18 insertions(+), 9 deletions(-)

diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index d60f7ed6a4..34d635006d 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -293,6 +293,22 @@ common_semi_flen_fstat_cb(CPUState *cs, uint64_t ret, int err)
     common_semi_cb(cs, ret, err);
 }
 
+static void
+common_semi_readc_cb(CPUState *cs, uint64_t ret, int err)
+{
+    if (!err) {
+        CPUArchState *env G_GNUC_UNUSED = cs->env_ptr;
+        uint8_t ch;
+
+        if (get_user_u8(ch, common_semi_stack_bottom(cs) - 1)) {
+            ret = -1, err = EFAULT;
+        } else {
+            ret = ch;
+        }
+    }
+    common_semi_cb(cs, ret, err);
+}
+
 #define SHFB_MAGIC_0 0x53
 #define SHFB_MAGIC_1 0x48
 #define SHFB_MAGIC_2 0x46
@@ -418,15 +434,8 @@ void do_common_semihosting(CPUState *cs)
         break;
 
     case TARGET_SYS_READC:
-        {
-            uint8_t ch;
-            int ret = qemu_semihosting_console_read(cs, &ch, 1);
-            if (ret == 1) {
-                common_semi_cb(cs, ch, 0);
-            } else {
-                common_semi_cb(cs, -1, EIO);
-            }
-        }
+        semihost_sys_read_gf(cs, common_semi_readc_cb, &console_in_gf,
+                             common_semi_stack_bottom(cs) - 1, 1);
         break;
 
     case TARGET_SYS_ISERROR:
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 43/74] semihosting: Use console_out_gf for SYS_WRITEC
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (41 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 42/74] semihosting: Use console_in_gf for SYS_READC Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 44/74] semihosting: Remove qemu_semihosting_console_outc Richard Henderson
                   ` (30 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 semihosting/arm-compat-semi.c | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index 34d635006d..430cb4167b 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -230,6 +230,15 @@ static void common_semi_cb(CPUState *cs, uint64_t ret, int err)
     common_semi_set_ret(cs, ret);
 }
 
+/*
+ * Use 0xdeadbeef as the return value when there isn't a defined
+ * return value for the call.
+ */
+static void common_semi_dead_cb(CPUState *cs, uint64_t ret, int err)
+{
+    common_semi_set_ret(cs, 0xdeadbeef);
+}
+
 /*
  * SYS_READ and SYS_WRITE always return the number of bytes not read/written.
  * There is no error condition, other than returning the original length.
@@ -332,8 +341,7 @@ static const uint8_t featurefile_data[] = {
  * The specification always says that the "return register" either
  * returns a specific value or is corrupted, so we don't need to
  * report to our caller whether we are returning a value or trying to
- * leave the register unchanged. We use 0xdeadbeef as the return value
- * when there isn't a defined return value for the call.
+ * leave the register unchanged.
  */
 void do_common_semihosting(CPUState *cs)
 {
@@ -410,8 +418,12 @@ void do_common_semihosting(CPUState *cs)
         break;
 
     case TARGET_SYS_WRITEC:
-        qemu_semihosting_console_outc(env, args);
-        common_semi_set_ret(cs, 0xdeadbeef);
+        /*
+         * FIXME: the byte to be written is in a target_ulong slot,
+         * which means this is wrong for a big-endian guest.
+         */
+        semihost_sys_write_gf(cs, common_semi_dead_cb,
+                              &console_out_gf, args, 1);
         break;
 
     case TARGET_SYS_WRITE0:
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 44/74] semihosting: Remove qemu_semihosting_console_outc
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (42 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 43/74] semihosting: Use console_out_gf for SYS_WRITEC Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 45/74] semihosting: Use console_out_gf for SYS_WRITE0 Richard Henderson
                   ` (29 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

This function has been replaced by *_write.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/semihosting/console.h | 13 -------------
 linux-user/semihost.c         | 16 ----------------
 semihosting/console.c         | 18 ------------------
 3 files changed, 47 deletions(-)

diff --git a/include/semihosting/console.h b/include/semihosting/console.h
index 6994f23c82..d6c1cc58ab 100644
--- a/include/semihosting/console.h
+++ b/include/semihosting/console.h
@@ -24,19 +24,6 @@
  */
 int qemu_semihosting_console_outs(CPUArchState *env, target_ulong s);
 
-/**
- * qemu_semihosting_console_outc:
- * @env: CPUArchState
- * @s: host address of null terminated guest string
- *
- * Send single character from guest memory to the debug console. This
- * may be the remote gdb session if a softmmu guest is currently being
- * debugged.
- *
- * Returns: nothing
- */
-void qemu_semihosting_console_outc(CPUArchState *env, target_ulong c);
-
 /**
  * qemu_semihosting_console_read:
  * @cs: CPUState
diff --git a/linux-user/semihost.c b/linux-user/semihost.c
index 871edf993a..f8bc8889f3 100644
--- a/linux-user/semihost.c
+++ b/linux-user/semihost.c
@@ -33,22 +33,6 @@ int qemu_semihosting_console_outs(CPUArchState *env, target_ulong addr)
     return len;
 }
 
-void qemu_semihosting_console_outc(CPUArchState *env, target_ulong addr)
-{
-    char c;
-
-    if (get_user_u8(c, addr)) {
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "%s: passed inaccessible address " TARGET_FMT_lx,
-                      __func__, addr);
-    } else {
-        if (write(STDERR_FILENO, &c, 1) != 1) {
-            qemu_log_mask(LOG_UNIMP, "%s: unexpected write to stdout failure",
-                          __func__);
-        }
-    }
-}
-
 /*
  * For linux-user we can safely block. However as we want to return as
  * soon as a character is read we need to tweak the termio to disable
diff --git a/semihosting/console.c b/semihosting/console.c
index 677ec2b176..f6fab5933a 100644
--- a/semihosting/console.c
+++ b/semihosting/console.c
@@ -96,24 +96,6 @@ int qemu_semihosting_console_outs(CPUArchState *env, target_ulong addr)
     return out;
 }
 
-void qemu_semihosting_console_outc(CPUArchState *env, target_ulong addr)
-{
-    CPUState *cpu = env_cpu(env);
-    uint8_t c;
-
-    if (cpu_memory_rw_debug(cpu, addr, &c, 1, 0) == 0) {
-        if (use_gdb_syscalls()) {
-            gdb_do_syscall(semihosting_cb, "write,2,%x,%x", addr, 1);
-        } else {
-            qemu_semihosting_log_out((const char *) &c, 1);
-        }
-    } else {
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "%s: passed inaccessible address " TARGET_FMT_lx,
-                      __func__, addr);
-    }
-}
-
 #define FIFO_SIZE   1024
 
 static int console_can_read(void *opaque)
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 45/74] semihosting: Use console_out_gf for SYS_WRITE0
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (43 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 44/74] semihosting: Remove qemu_semihosting_console_outc Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 46/74] semihosting: Remove qemu_semihosting_console_outs Richard Henderson
                   ` (28 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 semihosting/arm-compat-semi.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index 430cb4167b..3f8e1b70d1 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -427,8 +427,15 @@ void do_common_semihosting(CPUState *cs)
         break;
 
     case TARGET_SYS_WRITE0:
-        ret = qemu_semihosting_console_outs(env, args);
-        common_semi_set_ret(cs, ret);
+        {
+            ssize_t len = target_strlen(args);
+            if (len < 0) {
+                common_semi_dead_cb(cs, -1, EFAULT);
+            } else {
+                semihost_sys_write_gf(cs, common_semi_dead_cb,
+                                      &console_out_gf, args, len);
+            }
+        }
         break;
 
     case TARGET_SYS_WRITE:
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 46/74] semihosting: Remove qemu_semihosting_console_outs
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (44 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 45/74] semihosting: Use console_out_gf for SYS_WRITE0 Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 47/74] semihosting: Create semihost_sys_poll_one Richard Henderson
                   ` (27 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

This function has been replaced by *_write.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/semihosting/console.h | 13 ----------
 linux-user/semihost.c         | 17 ------------
 semihosting/console.c         | 49 -----------------------------------
 3 files changed, 79 deletions(-)

diff --git a/include/semihosting/console.h b/include/semihosting/console.h
index d6c1cc58ab..20c31d89d4 100644
--- a/include/semihosting/console.h
+++ b/include/semihosting/console.h
@@ -11,19 +11,6 @@
 
 #include "cpu.h"
 
-/**
- * qemu_semihosting_console_outs:
- * @env: CPUArchState
- * @s: host address of null terminated guest string
- *
- * Send a null terminated guest string to the debug console. This may
- * be the remote gdb session if a softmmu guest is currently being
- * debugged.
- *
- * Returns: number of bytes written.
- */
-int qemu_semihosting_console_outs(CPUArchState *env, target_ulong s);
-
 /**
  * qemu_semihosting_console_read:
  * @cs: CPUState
diff --git a/linux-user/semihost.c b/linux-user/semihost.c
index f8bc8889f3..cee62a365c 100644
--- a/linux-user/semihost.c
+++ b/linux-user/semihost.c
@@ -16,23 +16,6 @@
 #include "user-internals.h"
 #include <termios.h>
 
-int qemu_semihosting_console_outs(CPUArchState *env, target_ulong addr)
-{
-    int len = target_strlen(addr);
-    void *s;
-    if (len < 0){
-       qemu_log_mask(LOG_GUEST_ERROR,
-                     "%s: passed inaccessible address " TARGET_FMT_lx,
-                     __func__, addr);
-       return 0;
-    }
-    s = lock_user(VERIFY_READ, addr, (long)(len + 1), 1);
-    g_assert(s);  /* target_strlen has already verified this will work */
-    len = write(STDERR_FILENO, s, len);
-    unlock_user(s, addr, 0);
-    return len;
-}
-
 /*
  * For linux-user we can safely block. However as we want to return as
  * soon as a character is read we need to tweak the termio to disable
diff --git a/semihosting/console.c b/semihosting/console.c
index f6fab5933a..c84ab97ab6 100644
--- a/semihosting/console.c
+++ b/semihosting/console.c
@@ -47,55 +47,6 @@ int qemu_semihosting_log_out(const char *s, int len)
     }
 }
 
-/*
- * A re-implementation of lock_user_string that we can use locally
- * instead of relying on softmmu-semi. Hopefully we can deprecate that
- * in time. Copy string until we find a 0 or address error.
- */
-static GString *copy_user_string(CPUArchState *env, target_ulong addr)
-{
-    CPUState *cpu = env_cpu(env);
-    GString *s = g_string_sized_new(128);
-    uint8_t c;
-
-    do {
-        if (cpu_memory_rw_debug(cpu, addr++, &c, 1, 0) == 0) {
-            if (c) {
-                s = g_string_append_c(s, c);
-            }
-        } else {
-            qemu_log_mask(LOG_GUEST_ERROR,
-                          "%s: passed inaccessible address " TARGET_FMT_lx,
-                          __func__, addr);
-            break;
-        }
-    } while (c!=0);
-
-    return s;
-}
-
-static void semihosting_cb(CPUState *cs, uint64_t ret, int err)
-{
-    if (err) {
-        qemu_log("%s: gdb console output failed (%d)", __func__, err);
-    }
-}
-
-int qemu_semihosting_console_outs(CPUArchState *env, target_ulong addr)
-{
-    GString *s = copy_user_string(env, addr);
-    int out = s->len;
-
-    if (use_gdb_syscalls()) {
-        gdb_do_syscall(semihosting_cb, "write,2,%x,%x", addr, s->len);
-    } else {
-        out = qemu_semihosting_log_out(s->str, s->len);
-    }
-
-    g_string_free(s, true);
-    return out;
-}
-
 #define FIFO_SIZE   1024
 
 static int console_can_read(void *opaque)
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 47/74] semihosting: Create semihost_sys_poll_one
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (45 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 46/74] semihosting: Remove qemu_semihosting_console_outs Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 48/74] target/m68k: Eliminate m68k_semi_is_fseek Richard Henderson
                   ` (26 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

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(-)

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 aa4ee47649..1b87c37437 100644
--- a/semihosting/syscalls.c
+++ b/semihosting/syscalls.c
@@ -550,6 +550,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.
  */
@@ -658,6 +673,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.
  */
@@ -936,3 +979,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



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 48/74] target/m68k: Eliminate m68k_semi_is_fseek
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (46 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 47/74] semihosting: Create semihost_sys_poll_one Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 49/74] target/m68k: Make semihosting system only Richard Henderson
                   ` (25 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

Reorg m68k_semi_return_* to gdb_syscall_complete_cb.
Use the 32-bit version normally, and the 64-bit version
for HOSTED_LSEEK.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/m68k/m68k-semi.c | 55 +++++++++++++++++------------------------
 1 file changed, 23 insertions(+), 32 deletions(-)

diff --git a/target/m68k/m68k-semi.c b/target/m68k/m68k-semi.c
index 94deebf09e..5b4c51957e 100644
--- a/target/m68k/m68k-semi.c
+++ b/target/m68k/m68k-semi.c
@@ -93,8 +93,11 @@ static void translate_stat(CPUM68KState *env, target_ulong addr, struct stat *s)
     unlock_user(p, addr, sizeof(struct gdb_stat));
 }
 
-static void m68k_semi_return_u32(CPUM68KState *env, uint32_t ret, int err)
+static void m68k_semi_u32_cb(CPUState *cs, uint64_t ret, int err)
 {
+    M68kCPU *cpu = M68K_CPU(cs);
+    CPUM68KState *env = &cpu->env;
+
     target_ulong args = env->dregs[1];
     if (put_user_u32(ret, args) ||
         put_user_u32(err, args + 4)) {
@@ -108,8 +111,11 @@ static void m68k_semi_return_u32(CPUM68KState *env, uint32_t ret, int err)
     }
 }
 
-static void m68k_semi_return_u64(CPUM68KState *env, uint64_t ret, int err)
+static void m68k_semi_u64_cb(CPUState *cs, uint64_t ret, int err)
 {
+    M68kCPU *cpu = M68K_CPU(cs);
+    CPUM68KState *env = &cpu->env;
+
     target_ulong args = env->dregs[1];
     if (put_user_u32(ret >> 32, args) ||
         put_user_u32(ret, args + 4) ||
@@ -120,21 +126,6 @@ static void m68k_semi_return_u64(CPUM68KState *env, uint64_t ret, int err)
     }
 }
 
-static int m68k_semi_is_fseek;
-
-static void m68k_semi_cb(CPUState *cs, uint64_t ret, int err)
-{
-    M68kCPU *cpu = M68K_CPU(cs);
-    CPUM68KState *env = &cpu->env;
-
-    if (m68k_semi_is_fseek) {
-        m68k_semi_return_u64(env, ret, err);
-        m68k_semi_is_fseek = 0;
-    } else {
-        m68k_semi_return_u32(env, ret, err);
-    }
-}
-
 /*
  * Read the input value from the argument block; fail the semihosting
  * call if the memory read fails.
@@ -149,6 +140,7 @@ static void m68k_semi_cb(CPUState *cs, uint64_t ret, int err)
 
 void do_m68k_semihosting(CPUM68KState *env, int nr)
 {
+    CPUState *cs = env_cpu(env);
     uint32_t args;
     target_ulong arg0, arg1, arg2, arg3;
     void *p;
@@ -167,7 +159,7 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
         GET_ARG(2);
         GET_ARG(3);
         if (use_gdb_syscalls()) {
-            gdb_do_syscall(m68k_semi_cb, "open,%s,%x,%x", arg0, (int)arg1,
+            gdb_do_syscall(m68k_semi_u32_cb, "open,%s,%x,%x", arg0, (int)arg1,
                            arg2, arg3);
             return;
         } else {
@@ -188,7 +180,7 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
             int fd = arg0;
             if (fd > 2) {
                 if (use_gdb_syscalls()) {
-                    gdb_do_syscall(m68k_semi_cb, "close,%x", arg0);
+                    gdb_do_syscall(m68k_semi_u32_cb, "close,%x", arg0);
                     return;
                 } else {
                     result = close(fd);
@@ -204,7 +196,7 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
         GET_ARG(2);
         len = arg2;
         if (use_gdb_syscalls()) {
-            gdb_do_syscall(m68k_semi_cb, "read,%x,%x,%x",
+            gdb_do_syscall(m68k_semi_u32_cb, "read,%x,%x,%x",
                            arg0, arg1, len);
             return;
         } else {
@@ -224,7 +216,7 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
         GET_ARG(2);
         len = arg2;
         if (use_gdb_syscalls()) {
-            gdb_do_syscall(m68k_semi_cb, "write,%x,%x,%x",
+            gdb_do_syscall(m68k_semi_u32_cb, "write,%x,%x,%x",
                            arg0, arg1, len);
             return;
         } else {
@@ -247,12 +239,11 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
             GET_ARG(3);
             off = (uint32_t)arg2 | ((uint64_t)arg1 << 32);
             if (use_gdb_syscalls()) {
-                m68k_semi_is_fseek = 1;
-                gdb_do_syscall(m68k_semi_cb, "fseek,%x,%lx,%x",
+                gdb_do_syscall(m68k_semi_u64_cb, "fseek,%x,%lx,%x",
                                arg0, off, arg3);
             } else {
                 off = lseek(arg0, off, arg3);
-                m68k_semi_return_u64(env, off, errno);
+                m68k_semi_u64_cb(cs, off, errno);
             }
             return;
         }
@@ -262,7 +253,7 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
         GET_ARG(2);
         GET_ARG(3);
         if (use_gdb_syscalls()) {
-            gdb_do_syscall(m68k_semi_cb, "rename,%s,%s",
+            gdb_do_syscall(m68k_semi_u32_cb, "rename,%s,%s",
                            arg0, (int)arg1, arg2, (int)arg3);
             return;
         } else {
@@ -282,7 +273,7 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
         GET_ARG(0);
         GET_ARG(1);
         if (use_gdb_syscalls()) {
-            gdb_do_syscall(m68k_semi_cb, "unlink,%s",
+            gdb_do_syscall(m68k_semi_u32_cb, "unlink,%s",
                            arg0, (int)arg1);
             return;
         } else {
@@ -301,7 +292,7 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
         GET_ARG(1);
         GET_ARG(2);
         if (use_gdb_syscalls()) {
-            gdb_do_syscall(m68k_semi_cb, "stat,%s,%x",
+            gdb_do_syscall(m68k_semi_u32_cb, "stat,%s,%x",
                            arg0, (int)arg1, arg2);
             return;
         } else {
@@ -323,7 +314,7 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
         GET_ARG(0);
         GET_ARG(1);
         if (use_gdb_syscalls()) {
-            gdb_do_syscall(m68k_semi_cb, "fstat,%x,%x",
+            gdb_do_syscall(m68k_semi_u32_cb, "fstat,%x,%x",
                            arg0, arg1);
             return;
         } else {
@@ -338,7 +329,7 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
         GET_ARG(0);
         GET_ARG(1);
         if (use_gdb_syscalls()) {
-            gdb_do_syscall(m68k_semi_cb, "gettimeofday,%x,%x",
+            gdb_do_syscall(m68k_semi_u32_cb, "gettimeofday,%x,%x",
                            arg0, arg1);
             return;
         } else {
@@ -359,7 +350,7 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
     case HOSTED_ISATTY:
         GET_ARG(0);
         if (use_gdb_syscalls()) {
-            gdb_do_syscall(m68k_semi_cb, "isatty,%x", arg0);
+            gdb_do_syscall(m68k_semi_u32_cb, "isatty,%x", arg0);
             return;
         } else {
             result = isatty(arg0);
@@ -369,7 +360,7 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
         GET_ARG(0);
         GET_ARG(1);
         if (use_gdb_syscalls()) {
-            gdb_do_syscall(m68k_semi_cb, "system,%s",
+            gdb_do_syscall(m68k_semi_u32_cb, "system,%s",
                            arg0, (int)arg1);
             return;
         } else {
@@ -427,5 +418,5 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
         result = 0;
     }
 failed:
-    m68k_semi_return_u32(env, result, errno);
+    m68k_semi_u32_cb(cs, result, errno);
 }
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 49/74] target/m68k: Make semihosting system only
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (47 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 48/74] target/m68k: Eliminate m68k_semi_is_fseek Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 50/74] target/m68k: Use semihosting/syscalls.h Richard Henderson
                   ` (24 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

While we had a call to do_m68k_semihosting in linux-user, it
wasn't actually reachable.  We don't include DISAS_INSN(halt)
as an instruction unless system mode.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/m68k/cpu_loop.c |  5 -----
 target/m68k/m68k-semi.c    | 37 +------------------------------------
 target/m68k/meson.build    |  6 ++++--
 3 files changed, 5 insertions(+), 43 deletions(-)

diff --git a/linux-user/m68k/cpu_loop.c b/linux-user/m68k/cpu_loop.c
index d1bf8548b7..fa6aa112cb 100644
--- a/linux-user/m68k/cpu_loop.c
+++ b/linux-user/m68k/cpu_loop.c
@@ -36,11 +36,6 @@ void cpu_loop(CPUM68KState *env)
         process_queued_cpu_work(cs);
 
         switch(trapnr) {
-        case EXCP_HALT_INSN:
-            /* Semihosing syscall.  */
-            env->pc += 4;
-            do_m68k_semihosting(env, env->dregs[0]);
-            break;
         case EXCP_ILLEGAL:
         case EXCP_LINEA:
         case EXCP_LINEF:
diff --git a/target/m68k/m68k-semi.c b/target/m68k/m68k-semi.c
index 5b4c51957e..4b5621a101 100644
--- a/target/m68k/m68k-semi.c
+++ b/target/m68k/m68k-semi.c
@@ -21,13 +21,9 @@
 
 #include "cpu.h"
 #include "exec/gdbstub.h"
-#if defined(CONFIG_USER_ONLY)
-#include "qemu.h"
-#define SEMIHOSTING_HEAP_SIZE (128 * 1024 * 1024)
-#else
+#include "semihosting/guestfd.h"
 #include "semihosting/softmmu-uaccess.h"
 #include "hw/boards.h"
-#endif
 #include "qemu/log.h"
 
 #define HOSTED_EXIT  0
@@ -375,43 +371,12 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
         }
         break;
     case HOSTED_INIT_SIM:
-#if defined(CONFIG_USER_ONLY)
-        {
-        CPUState *cs = env_cpu(env);
-        TaskState *ts = cs->opaque;
-        /* Allocate the heap using sbrk.  */
-        if (!ts->heap_limit) {
-            abi_ulong ret;
-            uint32_t size;
-            uint32_t base;
-
-            base = do_brk(0);
-            size = SEMIHOSTING_HEAP_SIZE;
-            /* Try a big heap, and reduce the size if that fails.  */
-            for (;;) {
-                ret = do_brk(base + size);
-                if (ret >= (base + size)) {
-                    break;
-                }
-                size >>= 1;
-            }
-            ts->heap_limit = base + size;
-        }
-        /*
-         * This call may happen before we have writable memory, so return
-         * values directly in registers.
-         */
-        env->dregs[1] = ts->heap_limit;
-        env->aregs[7] = ts->stack_base;
-        }
-#else
         /*
          * FIXME: This is wrong for boards where RAM does not start at
          * address zero.
          */
         env->dregs[1] = current_machine->ram_size;
         env->aregs[7] = current_machine->ram_size;
-#endif
         return;
     default:
         cpu_abort(env_cpu(env), "Unsupported semihosting syscall %d\n", nr);
diff --git a/target/m68k/meson.build b/target/m68k/meson.build
index 05cd9fbd1e..27d2d7ba87 100644
--- a/target/m68k/meson.build
+++ b/target/m68k/meson.build
@@ -4,14 +4,16 @@ m68k_ss.add(files(
   'fpu_helper.c',
   'gdbstub.c',
   'helper.c',
-  'm68k-semi.c',
   'op_helper.c',
   'softfloat.c',
   'translate.c',
 ))
 
 m68k_softmmu_ss = ss.source_set()
-m68k_softmmu_ss.add(files('monitor.c'))
+m68k_softmmu_ss.add(files(
+  'm68k-semi.c',
+  'monitor.c'
+))
 
 target_arch += {'m68k': m68k_ss}
 target_softmmu_arch += {'m68k': m68k_softmmu_ss}
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 50/74] target/m68k: Use semihosting/syscalls.h
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (48 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 49/74] target/m68k: Make semihosting system only Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 51/74] target/nios2: Eliminate nios2_semi_is_lseek Richard Henderson
                   ` (23 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

This separates guest file descriptors from host file descriptors,
and utilizes shared infrastructure for integration with gdbstub.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/m68k/m68k-semi.c | 270 ++++++----------------------------------
 1 file changed, 39 insertions(+), 231 deletions(-)

diff --git a/target/m68k/m68k-semi.c b/target/m68k/m68k-semi.c
index 4b5621a101..d6b3b3226e 100644
--- a/target/m68k/m68k-semi.c
+++ b/target/m68k/m68k-semi.c
@@ -21,7 +21,7 @@
 
 #include "cpu.h"
 #include "exec/gdbstub.h"
-#include "semihosting/guestfd.h"
+#include "semihosting/syscalls.h"
 #include "semihosting/softmmu-uaccess.h"
 #include "hw/boards.h"
 #include "qemu/log.h"
@@ -41,54 +41,6 @@
 #define HOSTED_ISATTY 12
 #define HOSTED_SYSTEM 13
 
-static int translate_openflags(int flags)
-{
-    int hf;
-
-    if (flags & GDB_O_WRONLY)
-        hf = O_WRONLY;
-    else if (flags & GDB_O_RDWR)
-        hf = O_RDWR;
-    else
-        hf = O_RDONLY;
-
-    if (flags & GDB_O_APPEND) hf |= O_APPEND;
-    if (flags & GDB_O_CREAT) hf |= O_CREAT;
-    if (flags & GDB_O_TRUNC) hf |= O_TRUNC;
-    if (flags & GDB_O_EXCL) hf |= O_EXCL;
-
-    return hf;
-}
-
-static void translate_stat(CPUM68KState *env, target_ulong addr, struct stat *s)
-{
-    struct gdb_stat *p;
-
-    if (!(p = lock_user(VERIFY_WRITE, addr, sizeof(struct gdb_stat), 0)))
-        /* FIXME - should this return an error code? */
-        return;
-    p->gdb_st_dev = cpu_to_be32(s->st_dev);
-    p->gdb_st_ino = cpu_to_be32(s->st_ino);
-    p->gdb_st_mode = cpu_to_be32(s->st_mode);
-    p->gdb_st_nlink = cpu_to_be32(s->st_nlink);
-    p->gdb_st_uid = cpu_to_be32(s->st_uid);
-    p->gdb_st_gid = cpu_to_be32(s->st_gid);
-    p->gdb_st_rdev = cpu_to_be32(s->st_rdev);
-    p->gdb_st_size = cpu_to_be64(s->st_size);
-#ifdef _WIN32
-    /* Windows stat is missing some fields.  */
-    p->gdb_st_blksize = 0;
-    p->gdb_st_blocks = 0;
-#else
-    p->gdb_st_blksize = cpu_to_be64(s->st_blksize);
-    p->gdb_st_blocks = cpu_to_be64(s->st_blocks);
-#endif
-    p->gdb_st_atime = cpu_to_be32(s->st_atime);
-    p->gdb_st_mtime = cpu_to_be32(s->st_mtime);
-    p->gdb_st_ctime = cpu_to_be32(s->st_ctime);
-    unlock_user(p, addr, sizeof(struct gdb_stat));
-}
-
 static void m68k_semi_u32_cb(CPUState *cs, uint64_t ret, int err)
 {
     M68kCPU *cpu = M68K_CPU(cs);
@@ -128,8 +80,6 @@ static void m68k_semi_u64_cb(CPUState *cs, uint64_t ret, int err)
  */
 #define GET_ARG(n) do {                                 \
     if (get_user_ual(arg ## n, args + (n) * 4)) {       \
-        result = -1;                                    \
-        errno = EFAULT;                                 \
         goto failed;                                    \
     }                                                   \
 } while (0)
@@ -139,237 +89,93 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
     CPUState *cs = env_cpu(env);
     uint32_t args;
     target_ulong arg0, arg1, arg2, arg3;
-    void *p;
-    void *q;
-    uint32_t len;
-    uint32_t result;
 
     args = env->dregs[1];
     switch (nr) {
     case HOSTED_EXIT:
         gdb_exit(env->dregs[0]);
         exit(env->dregs[0]);
+
     case HOSTED_OPEN:
         GET_ARG(0);
         GET_ARG(1);
         GET_ARG(2);
         GET_ARG(3);
-        if (use_gdb_syscalls()) {
-            gdb_do_syscall(m68k_semi_u32_cb, "open,%s,%x,%x", arg0, (int)arg1,
-                           arg2, arg3);
-            return;
-        } else {
-            p = lock_user_string(arg0);
-            if (!p) {
-                /* FIXME - check error code? */
-                result = -1;
-            } else {
-                result = open(p, translate_openflags(arg2), arg3);
-                unlock_user(p, arg0, 0);
-            }
-        }
+        semihost_sys_open(cs, m68k_semi_u32_cb, arg0, arg1, arg2, arg3);
         break;
+
     case HOSTED_CLOSE:
-        {
-            /* Ignore attempts to close stdin/out/err.  */
-            GET_ARG(0);
-            int fd = arg0;
-            if (fd > 2) {
-                if (use_gdb_syscalls()) {
-                    gdb_do_syscall(m68k_semi_u32_cb, "close,%x", arg0);
-                    return;
-                } else {
-                    result = close(fd);
-                }
-            } else {
-                result = 0;
-            }
-            break;
-        }
+        GET_ARG(0);
+        semihost_sys_close(cs, m68k_semi_u32_cb, arg0);
+        break;
+
     case HOSTED_READ:
         GET_ARG(0);
         GET_ARG(1);
         GET_ARG(2);
-        len = arg2;
-        if (use_gdb_syscalls()) {
-            gdb_do_syscall(m68k_semi_u32_cb, "read,%x,%x,%x",
-                           arg0, arg1, len);
-            return;
-        } else {
-            p = lock_user(VERIFY_WRITE, arg1, len, 0);
-            if (!p) {
-                /* FIXME - check error code? */
-                result = -1;
-            } else {
-                result = read(arg0, p, len);
-                unlock_user(p, arg1, len);
-            }
-        }
+        semihost_sys_read(cs, m68k_semi_u32_cb, arg0, arg1, arg2);
         break;
+
     case HOSTED_WRITE:
         GET_ARG(0);
         GET_ARG(1);
         GET_ARG(2);
-        len = arg2;
-        if (use_gdb_syscalls()) {
-            gdb_do_syscall(m68k_semi_u32_cb, "write,%x,%x,%x",
-                           arg0, arg1, len);
-            return;
-        } else {
-            p = lock_user(VERIFY_READ, arg1, len, 1);
-            if (!p) {
-                /* FIXME - check error code? */
-                result = -1;
-            } else {
-                result = write(arg0, p, len);
-                unlock_user(p, arg0, 0);
-            }
-        }
+        semihost_sys_write(cs, m68k_semi_u32_cb, arg0, arg1, arg2);
         break;
+
     case HOSTED_LSEEK:
-        {
-            uint64_t off;
-            GET_ARG(0);
-            GET_ARG(1);
-            GET_ARG(2);
-            GET_ARG(3);
-            off = (uint32_t)arg2 | ((uint64_t)arg1 << 32);
-            if (use_gdb_syscalls()) {
-                gdb_do_syscall(m68k_semi_u64_cb, "fseek,%x,%lx,%x",
-                               arg0, off, arg3);
-            } else {
-                off = lseek(arg0, off, arg3);
-                m68k_semi_u64_cb(cs, off, errno);
-            }
-            return;
-        }
+        GET_ARG(0);
+        GET_ARG(1);
+        GET_ARG(2);
+        GET_ARG(3);
+        semihost_sys_lseek(cs, m68k_semi_u64_cb, arg0,
+                           deposit64(arg2, arg1, 32, 32), arg3);
+        break;
+
     case HOSTED_RENAME:
         GET_ARG(0);
         GET_ARG(1);
         GET_ARG(2);
         GET_ARG(3);
-        if (use_gdb_syscalls()) {
-            gdb_do_syscall(m68k_semi_u32_cb, "rename,%s,%s",
-                           arg0, (int)arg1, arg2, (int)arg3);
-            return;
-        } else {
-            p = lock_user_string(arg0);
-            q = lock_user_string(arg2);
-            if (!p || !q) {
-                /* FIXME - check error code? */
-                result = -1;
-            } else {
-                result = rename(p, q);
-            }
-            unlock_user(p, arg0, 0);
-            unlock_user(q, arg2, 0);
-        }
+        semihost_sys_rename(cs, m68k_semi_u32_cb, arg0, arg1, arg2, arg3);
         break;
+
     case HOSTED_UNLINK:
         GET_ARG(0);
         GET_ARG(1);
-        if (use_gdb_syscalls()) {
-            gdb_do_syscall(m68k_semi_u32_cb, "unlink,%s",
-                           arg0, (int)arg1);
-            return;
-        } else {
-            p = lock_user_string(arg0);
-            if (!p) {
-                /* FIXME - check error code? */
-                result = -1;
-            } else {
-                result = unlink(p);
-                unlock_user(p, arg0, 0);
-            }
-        }
+        semihost_sys_remove(cs, m68k_semi_u32_cb, arg0, arg1);
         break;
+
     case HOSTED_STAT:
         GET_ARG(0);
         GET_ARG(1);
         GET_ARG(2);
-        if (use_gdb_syscalls()) {
-            gdb_do_syscall(m68k_semi_u32_cb, "stat,%s,%x",
-                           arg0, (int)arg1, arg2);
-            return;
-        } else {
-            struct stat s;
-            p = lock_user_string(arg0);
-            if (!p) {
-                /* FIXME - check error code? */
-                result = -1;
-            } else {
-                result = stat(p, &s);
-                unlock_user(p, arg0, 0);
-            }
-            if (result == 0) {
-                translate_stat(env, arg2, &s);
-            }
-        }
+        semihost_sys_stat(cs, m68k_semi_u32_cb, arg0, arg1, arg2);
         break;
+
     case HOSTED_FSTAT:
         GET_ARG(0);
         GET_ARG(1);
-        if (use_gdb_syscalls()) {
-            gdb_do_syscall(m68k_semi_u32_cb, "fstat,%x,%x",
-                           arg0, arg1);
-            return;
-        } else {
-            struct stat s;
-            result = fstat(arg0, &s);
-            if (result == 0) {
-                translate_stat(env, arg1, &s);
-            }
-        }
+        semihost_sys_fstat(cs, m68k_semi_u32_cb, arg0, arg1);
         break;
+
     case HOSTED_GETTIMEOFDAY:
         GET_ARG(0);
         GET_ARG(1);
-        if (use_gdb_syscalls()) {
-            gdb_do_syscall(m68k_semi_u32_cb, "gettimeofday,%x,%x",
-                           arg0, arg1);
-            return;
-        } else {
-            struct gdb_timeval *p;
-            int64_t rt = g_get_real_time();
-            p = lock_user(VERIFY_WRITE, arg0, sizeof(struct gdb_timeval), 0);
-            if (!p) {
-                /* FIXME - check error code? */
-                result = -1;
-            } else {
-                result = 0;
-                p->tv_sec = cpu_to_be32(rt / G_USEC_PER_SEC);
-                p->tv_usec = cpu_to_be64(rt % G_USEC_PER_SEC);
-                unlock_user(p, arg0, sizeof(struct gdb_timeval));
-            }
-        }
+        semihost_sys_gettimeofday(cs, m68k_semi_u32_cb, arg0, arg1);
         break;
+
     case HOSTED_ISATTY:
         GET_ARG(0);
-        if (use_gdb_syscalls()) {
-            gdb_do_syscall(m68k_semi_u32_cb, "isatty,%x", arg0);
-            return;
-        } else {
-            result = isatty(arg0);
-        }
+        semihost_sys_isatty(cs, m68k_semi_u32_cb, arg0);
         break;
+
     case HOSTED_SYSTEM:
         GET_ARG(0);
         GET_ARG(1);
-        if (use_gdb_syscalls()) {
-            gdb_do_syscall(m68k_semi_u32_cb, "system,%s",
-                           arg0, (int)arg1);
-            return;
-        } else {
-            p = lock_user_string(arg0);
-            if (!p) {
-                /* FIXME - check error code? */
-                result = -1;
-            } else {
-                result = system(p);
-                unlock_user(p, arg0, 0);
-            }
-        }
+        semihost_sys_system(cs, m68k_semi_u32_cb, arg0, arg1);
         break;
+
     case HOSTED_INIT_SIM:
         /*
          * FIXME: This is wrong for boards where RAM does not start at
@@ -378,10 +184,12 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
         env->dregs[1] = current_machine->ram_size;
         env->aregs[7] = current_machine->ram_size;
         return;
+
     default:
         cpu_abort(env_cpu(env), "Unsupported semihosting syscall %d\n", nr);
-        result = 0;
+
+    failed:
+        m68k_semi_u32_cb(cs, -1, EFAULT);
+        break;
     }
-failed:
-    m68k_semi_u32_cb(cs, result, errno);
 }
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 51/74] target/nios2: Eliminate nios2_semi_is_lseek
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (49 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 50/74] target/m68k: Use semihosting/syscalls.h Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 52/74] target/nios2: Move nios2-semi.c to nios2_softmmu_ss Richard Henderson
                   ` (22 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

Reorg nios2_semi_return_* to gdb_syscall_complete_cb.
Use the 32-bit version normally, and the 64-bit version
for HOSTED_LSEEK.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/nios2/nios2-semi.c | 59 +++++++++++++++------------------------
 1 file changed, 23 insertions(+), 36 deletions(-)

diff --git a/target/nios2/nios2-semi.c b/target/nios2/nios2-semi.c
index 4d02789d26..bdf8849689 100644
--- a/target/nios2/nios2-semi.c
+++ b/target/nios2/nios2-semi.c
@@ -108,9 +108,12 @@ static bool translate_stat(CPUNios2State *env, target_ulong addr,
     return true;
 }
 
-static void nios2_semi_return_u32(CPUNios2State *env, uint32_t ret, int err)
+static void nios2_semi_u32_cb(CPUState *cs, uint64_t ret, int err)
 {
+    Nios2CPU *cpu = NIOS2_CPU(cs);
+    CPUNios2State *env = &cpu->env;
     target_ulong args = env->regs[R_ARG1];
+
     if (put_user_u32(ret, args) ||
         put_user_u32(err, args + 4)) {
         /*
@@ -123,9 +126,12 @@ static void nios2_semi_return_u32(CPUNios2State *env, uint32_t ret, int err)
     }
 }
 
-static void nios2_semi_return_u64(CPUNios2State *env, uint64_t ret, int err)
+static void nios2_semi_u64_cb(CPUState *cs, uint64_t ret, int err)
 {
+    Nios2CPU *cpu = NIOS2_CPU(cs);
+    CPUNios2State *env = &cpu->env;
     target_ulong args = env->regs[R_ARG1];
+
     if (put_user_u32(ret >> 32, args) ||
         put_user_u32(ret, args + 4) ||
         put_user_u32(err, args + 8)) {
@@ -135,25 +141,6 @@ static void nios2_semi_return_u64(CPUNios2State *env, uint64_t ret, int err)
     }
 }
 
-static int nios2_semi_is_lseek;
-
-static void nios2_semi_cb(CPUState *cs, uint64_t ret, int err)
-{
-    Nios2CPU *cpu = NIOS2_CPU(cs);
-    CPUNios2State *env = &cpu->env;
-
-    if (nios2_semi_is_lseek) {
-        /*
-         * FIXME: We've already lost the high bits of the lseek
-         * return value.
-         */
-        nios2_semi_return_u64(env, ret, err);
-        nios2_semi_is_lseek = 0;
-    } else {
-        nios2_semi_return_u32(env, ret, err);
-    }
-}
-
 /*
  * Read the input value from the argument block; fail the semihosting
  * call if the memory read fails.
@@ -168,6 +155,7 @@ static void nios2_semi_cb(CPUState *cs, uint64_t ret, int err)
 
 void do_nios2_semihosting(CPUNios2State *env)
 {
+    CPUState *cs = env_cpu(env);
     int nr;
     uint32_t args;
     target_ulong arg0, arg1, arg2, arg3;
@@ -188,7 +176,7 @@ void do_nios2_semihosting(CPUNios2State *env)
         GET_ARG(2);
         GET_ARG(3);
         if (use_gdb_syscalls()) {
-            gdb_do_syscall(nios2_semi_cb, "open,%s,%x,%x", arg0, (int)arg1,
+            gdb_do_syscall(nios2_semi_u32_cb, "open,%s,%x,%x", arg0, (int)arg1,
                            arg2, arg3);
             return;
         } else {
@@ -209,7 +197,7 @@ void do_nios2_semihosting(CPUNios2State *env)
             int fd = arg0;
             if (fd > 2) {
                 if (use_gdb_syscalls()) {
-                    gdb_do_syscall(nios2_semi_cb, "close,%x", arg0);
+                    gdb_do_syscall(nios2_semi_u32_cb, "close,%x", arg0);
                     return;
                 } else {
                     result = close(fd);
@@ -225,7 +213,7 @@ void do_nios2_semihosting(CPUNios2State *env)
         GET_ARG(2);
         len = arg2;
         if (use_gdb_syscalls()) {
-            gdb_do_syscall(nios2_semi_cb, "read,%x,%x,%x",
+            gdb_do_syscall(nios2_semi_u32_cb, "read,%x,%x,%x",
                            arg0, arg1, len);
             return;
         } else {
@@ -245,7 +233,7 @@ void do_nios2_semihosting(CPUNios2State *env)
         GET_ARG(2);
         len = arg2;
         if (use_gdb_syscalls()) {
-            gdb_do_syscall(nios2_semi_cb, "write,%x,%x,%x",
+            gdb_do_syscall(nios2_semi_u32_cb, "write,%x,%x,%x",
                            arg0, arg1, len);
             return;
         } else {
@@ -268,12 +256,11 @@ void do_nios2_semihosting(CPUNios2State *env)
             GET_ARG(3);
             off = (uint32_t)arg2 | ((uint64_t)arg1 << 32);
             if (use_gdb_syscalls()) {
-                nios2_semi_is_lseek = 1;
-                gdb_do_syscall(nios2_semi_cb, "lseek,%x,%lx,%x",
+                gdb_do_syscall(nios2_semi_u64_cb, "lseek,%x,%lx,%x",
                                arg0, off, arg3);
             } else {
                 off = lseek(arg0, off, arg3);
-                nios2_semi_return_u64(env, off, errno);
+                nios2_semi_u64_cb(cs, off, errno);
             }
             return;
         }
@@ -283,7 +270,7 @@ void do_nios2_semihosting(CPUNios2State *env)
         GET_ARG(2);
         GET_ARG(3);
         if (use_gdb_syscalls()) {
-            gdb_do_syscall(nios2_semi_cb, "rename,%s,%s",
+            gdb_do_syscall(nios2_semi_u32_cb, "rename,%s,%s",
                            arg0, (int)arg1, arg2, (int)arg3);
             return;
         } else {
@@ -303,7 +290,7 @@ void do_nios2_semihosting(CPUNios2State *env)
         GET_ARG(0);
         GET_ARG(1);
         if (use_gdb_syscalls()) {
-            gdb_do_syscall(nios2_semi_cb, "unlink,%s",
+            gdb_do_syscall(nios2_semi_u32_cb, "unlink,%s",
                            arg0, (int)arg1);
             return;
         } else {
@@ -322,7 +309,7 @@ void do_nios2_semihosting(CPUNios2State *env)
         GET_ARG(1);
         GET_ARG(2);
         if (use_gdb_syscalls()) {
-            gdb_do_syscall(nios2_semi_cb, "stat,%s,%x",
+            gdb_do_syscall(nios2_semi_u32_cb, "stat,%s,%x",
                            arg0, (int)arg1, arg2);
             return;
         } else {
@@ -345,7 +332,7 @@ void do_nios2_semihosting(CPUNios2State *env)
         GET_ARG(0);
         GET_ARG(1);
         if (use_gdb_syscalls()) {
-            gdb_do_syscall(nios2_semi_cb, "fstat,%x,%x",
+            gdb_do_syscall(nios2_semi_u32_cb, "fstat,%x,%x",
                            arg0, arg1);
             return;
         } else {
@@ -361,7 +348,7 @@ void do_nios2_semihosting(CPUNios2State *env)
         /* Only the tv parameter is used.  tz is assumed NULL.  */
         GET_ARG(0);
         if (use_gdb_syscalls()) {
-            gdb_do_syscall(nios2_semi_cb, "gettimeofday,%x,%x",
+            gdb_do_syscall(nios2_semi_u32_cb, "gettimeofday,%x,%x",
                            arg0, 0);
             return;
         } else {
@@ -382,7 +369,7 @@ void do_nios2_semihosting(CPUNios2State *env)
     case HOSTED_ISATTY:
         GET_ARG(0);
         if (use_gdb_syscalls()) {
-            gdb_do_syscall(nios2_semi_cb, "isatty,%x", arg0);
+            gdb_do_syscall(nios2_semi_u32_cb, "isatty,%x", arg0);
             return;
         } else {
             result = isatty(arg0);
@@ -392,7 +379,7 @@ void do_nios2_semihosting(CPUNios2State *env)
         GET_ARG(0);
         GET_ARG(1);
         if (use_gdb_syscalls()) {
-            gdb_do_syscall(nios2_semi_cb, "system,%s",
+            gdb_do_syscall(nios2_semi_u32_cb, "system,%s",
                            arg0, (int)arg1);
             return;
         } else {
@@ -412,5 +399,5 @@ void do_nios2_semihosting(CPUNios2State *env)
         result = 0;
     }
 failed:
-    nios2_semi_return_u32(env, result, errno);
+    nios2_semi_u32_cb(cs, result, errno);
 }
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 52/74] target/nios2: Move nios2-semi.c to nios2_softmmu_ss
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (50 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 51/74] target/nios2: Eliminate nios2_semi_is_lseek Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 53/74] target/nios2: Use semihosting/syscalls.h Richard Henderson
                   ` (21 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

Semihosting is not enabled for nios2-linux-user.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/nios2/meson.build | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/target/nios2/meson.build b/target/nios2/meson.build
index 2bd60ba306..c6e2243cc3 100644
--- a/target/nios2/meson.build
+++ b/target/nios2/meson.build
@@ -1,7 +1,6 @@
 nios2_ss = ss.source_set()
 nios2_ss.add(files(
   'cpu.c',
-  'nios2-semi.c',
   'op_helper.c',
   'translate.c',
 ))
@@ -10,7 +9,8 @@ nios2_softmmu_ss = ss.source_set()
 nios2_softmmu_ss.add(files(
   'helper.c',
   'monitor.c',
-  'mmu.c'
+  'mmu.c',
+  'nios2-semi.c',
 ))
 
 target_arch += {'nios2': nios2_ss}
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 53/74] target/nios2: Use semihosting/syscalls.h
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (51 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 52/74] target/nios2: Move nios2-semi.c to nios2_softmmu_ss Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 54/74] target/mips: Use an exception for semihosting Richard Henderson
                   ` (20 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

This separates guest file descriptors from host file descriptors,
and utilizes shared infrastructure for integration with gdbstub.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/nios2/nios2-semi.c | 287 ++++++--------------------------------
 1 file changed, 41 insertions(+), 246 deletions(-)

diff --git a/target/nios2/nios2-semi.c b/target/nios2/nios2-semi.c
index bdf8849689..1b5afc9333 100644
--- a/target/nios2/nios2-semi.c
+++ b/target/nios2/nios2-semi.c
@@ -25,6 +25,7 @@
 
 #include "cpu.h"
 #include "exec/gdbstub.h"
+#include "semihosting/syscalls.h"
 #if defined(CONFIG_USER_ONLY)
 #include "qemu.h"
 #else
@@ -47,67 +48,6 @@
 #define HOSTED_ISATTY 12
 #define HOSTED_SYSTEM 13
 
-static int translate_openflags(int flags)
-{
-    int hf;
-
-    if (flags & GDB_O_WRONLY) {
-        hf = O_WRONLY;
-    } else if (flags & GDB_O_RDWR) {
-        hf = O_RDWR;
-    } else {
-        hf = O_RDONLY;
-    }
-
-    if (flags & GDB_O_APPEND) {
-        hf |= O_APPEND;
-    }
-    if (flags & GDB_O_CREAT) {
-        hf |= O_CREAT;
-    }
-    if (flags & GDB_O_TRUNC) {
-        hf |= O_TRUNC;
-    }
-    if (flags & GDB_O_EXCL) {
-        hf |= O_EXCL;
-    }
-
-    return hf;
-}
-
-static bool translate_stat(CPUNios2State *env, target_ulong addr,
-                           struct stat *s)
-{
-    struct gdb_stat *p;
-
-    p = lock_user(VERIFY_WRITE, addr, sizeof(struct gdb_stat), 0);
-
-    if (!p) {
-        return false;
-    }
-    p->gdb_st_dev = cpu_to_be32(s->st_dev);
-    p->gdb_st_ino = cpu_to_be32(s->st_ino);
-    p->gdb_st_mode = cpu_to_be32(s->st_mode);
-    p->gdb_st_nlink = cpu_to_be32(s->st_nlink);
-    p->gdb_st_uid = cpu_to_be32(s->st_uid);
-    p->gdb_st_gid = cpu_to_be32(s->st_gid);
-    p->gdb_st_rdev = cpu_to_be32(s->st_rdev);
-    p->gdb_st_size = cpu_to_be64(s->st_size);
-#ifdef _WIN32
-    /* Windows stat is missing some fields.  */
-    p->gdb_st_blksize = 0;
-    p->gdb_st_blocks = 0;
-#else
-    p->gdb_st_blksize = cpu_to_be64(s->st_blksize);
-    p->gdb_st_blocks = cpu_to_be64(s->st_blocks);
-#endif
-    p->gdb_st_atime = cpu_to_be32(s->st_atime);
-    p->gdb_st_mtime = cpu_to_be32(s->st_mtime);
-    p->gdb_st_ctime = cpu_to_be32(s->st_ctime);
-    unlock_user(p, addr, sizeof(struct gdb_stat));
-    return true;
-}
-
 static void nios2_semi_u32_cb(CPUState *cs, uint64_t ret, int err)
 {
     Nios2CPU *cpu = NIOS2_CPU(cs);
@@ -147,8 +87,6 @@ static void nios2_semi_u64_cb(CPUState *cs, uint64_t ret, int err)
  */
 #define GET_ARG(n) do {                                 \
     if (get_user_ual(arg ## n, args + (n) * 4)) {       \
-        result = -1;                                    \
-        errno = EFAULT;                                 \
         goto failed;                                    \
     }                                                   \
 } while (0)
@@ -159,10 +97,6 @@ void do_nios2_semihosting(CPUNios2State *env)
     int nr;
     uint32_t args;
     target_ulong arg0, arg1, arg2, arg3;
-    void *p;
-    void *q;
-    uint32_t len;
-    uint32_t result;
 
     nr = env->regs[R_ARG0];
     args = env->regs[R_ARG1];
@@ -170,234 +104,95 @@ void do_nios2_semihosting(CPUNios2State *env)
     case HOSTED_EXIT:
         gdb_exit(env->regs[R_ARG0]);
         exit(env->regs[R_ARG0]);
+
     case HOSTED_OPEN:
         GET_ARG(0);
         GET_ARG(1);
         GET_ARG(2);
         GET_ARG(3);
-        if (use_gdb_syscalls()) {
-            gdb_do_syscall(nios2_semi_u32_cb, "open,%s,%x,%x", arg0, (int)arg1,
-                           arg2, arg3);
-            return;
-        } else {
-            p = lock_user_string(arg0);
-            if (!p) {
-                result = -1;
-                errno = EFAULT;
-            } else {
-                result = open(p, translate_openflags(arg2), arg3);
-                unlock_user(p, arg0, 0);
-            }
-        }
+        semihost_sys_open(cs, nios2_semi_u32_cb, arg0, arg1, arg2, arg3);
         break;
+
     case HOSTED_CLOSE:
-        {
-            /* Ignore attempts to close stdin/out/err.  */
-            GET_ARG(0);
-            int fd = arg0;
-            if (fd > 2) {
-                if (use_gdb_syscalls()) {
-                    gdb_do_syscall(nios2_semi_u32_cb, "close,%x", arg0);
-                    return;
-                } else {
-                    result = close(fd);
-                }
-            } else {
-                result = 0;
-            }
-            break;
-        }
+        GET_ARG(0);
+        semihost_sys_close(cs, nios2_semi_u32_cb, arg0);
+        break;
+
     case HOSTED_READ:
         GET_ARG(0);
         GET_ARG(1);
         GET_ARG(2);
-        len = arg2;
-        if (use_gdb_syscalls()) {
-            gdb_do_syscall(nios2_semi_u32_cb, "read,%x,%x,%x",
-                           arg0, arg1, len);
-            return;
-        } else {
-            p = lock_user(VERIFY_WRITE, arg1, len, 0);
-            if (!p) {
-                result = -1;
-                errno = EFAULT;
-            } else {
-                result = read(arg0, p, len);
-                unlock_user(p, arg1, len);
-            }
-        }
+        semihost_sys_read(cs, nios2_semi_u32_cb, arg0, arg1, arg2);
         break;
+
     case HOSTED_WRITE:
         GET_ARG(0);
         GET_ARG(1);
         GET_ARG(2);
-        len = arg2;
-        if (use_gdb_syscalls()) {
-            gdb_do_syscall(nios2_semi_u32_cb, "write,%x,%x,%x",
-                           arg0, arg1, len);
-            return;
-        } else {
-            p = lock_user(VERIFY_READ, arg1, len, 1);
-            if (!p) {
-                result = -1;
-                errno = EFAULT;
-            } else {
-                result = write(arg0, p, len);
-                unlock_user(p, arg0, 0);
-            }
-        }
+        semihost_sys_write(cs, nios2_semi_u32_cb, arg0, arg1, arg2);
         break;
+
     case HOSTED_LSEEK:
-        {
-            uint64_t off;
-            GET_ARG(0);
-            GET_ARG(1);
-            GET_ARG(2);
-            GET_ARG(3);
-            off = (uint32_t)arg2 | ((uint64_t)arg1 << 32);
-            if (use_gdb_syscalls()) {
-                gdb_do_syscall(nios2_semi_u64_cb, "lseek,%x,%lx,%x",
-                               arg0, off, arg3);
-            } else {
-                off = lseek(arg0, off, arg3);
-                nios2_semi_u64_cb(cs, off, errno);
-            }
-            return;
-        }
+        GET_ARG(0);
+        GET_ARG(1);
+        GET_ARG(2);
+        GET_ARG(3);
+        semihost_sys_lseek(cs, nios2_semi_u64_cb, arg0,
+                           deposit64(arg2, arg1, 32, 32), arg3);
+        break;
+
     case HOSTED_RENAME:
         GET_ARG(0);
         GET_ARG(1);
         GET_ARG(2);
         GET_ARG(3);
-        if (use_gdb_syscalls()) {
-            gdb_do_syscall(nios2_semi_u32_cb, "rename,%s,%s",
-                           arg0, (int)arg1, arg2, (int)arg3);
-            return;
-        } else {
-            p = lock_user_string(arg0);
-            q = lock_user_string(arg2);
-            if (!p || !q) {
-                result = -1;
-                errno = EFAULT;
-            } else {
-                result = rename(p, q);
-            }
-            unlock_user(p, arg0, 0);
-            unlock_user(q, arg2, 0);
-        }
+        semihost_sys_rename(cs, nios2_semi_u32_cb, arg0, arg1, arg2, arg3);
         break;
+
     case HOSTED_UNLINK:
         GET_ARG(0);
         GET_ARG(1);
-        if (use_gdb_syscalls()) {
-            gdb_do_syscall(nios2_semi_u32_cb, "unlink,%s",
-                           arg0, (int)arg1);
-            return;
-        } else {
-            p = lock_user_string(arg0);
-            if (!p) {
-                result = -1;
-                errno = EFAULT;
-            } else {
-                result = unlink(p);
-                unlock_user(p, arg0, 0);
-            }
-        }
+        semihost_sys_remove(cs, nios2_semi_u32_cb, arg0, arg1);
         break;
+
     case HOSTED_STAT:
         GET_ARG(0);
         GET_ARG(1);
         GET_ARG(2);
-        if (use_gdb_syscalls()) {
-            gdb_do_syscall(nios2_semi_u32_cb, "stat,%s,%x",
-                           arg0, (int)arg1, arg2);
-            return;
-        } else {
-            struct stat s;
-            p = lock_user_string(arg0);
-            if (!p) {
-                result = -1;
-                errno = EFAULT;
-            } else {
-                result = stat(p, &s);
-                unlock_user(p, arg0, 0);
-            }
-            if (result == 0 && !translate_stat(env, arg2, &s)) {
-                result = -1;
-                errno = EFAULT;
-            }
-        }
+        semihost_sys_stat(cs, nios2_semi_u32_cb, arg0, arg1, arg2);
         break;
+
     case HOSTED_FSTAT:
         GET_ARG(0);
         GET_ARG(1);
-        if (use_gdb_syscalls()) {
-            gdb_do_syscall(nios2_semi_u32_cb, "fstat,%x,%x",
-                           arg0, arg1);
-            return;
-        } else {
-            struct stat s;
-            result = fstat(arg0, &s);
-            if (result == 0 && !translate_stat(env, arg1, &s)) {
-                result = -1;
-                errno = EFAULT;
-            }
-        }
+        semihost_sys_fstat(cs, nios2_semi_u32_cb, arg0, arg1);
         break;
+
     case HOSTED_GETTIMEOFDAY:
-        /* Only the tv parameter is used.  tz is assumed NULL.  */
         GET_ARG(0);
-        if (use_gdb_syscalls()) {
-            gdb_do_syscall(nios2_semi_u32_cb, "gettimeofday,%x,%x",
-                           arg0, 0);
-            return;
-        } else {
-            struct gdb_timeval *p;
-            int64_t rt = g_get_real_time();
-            p = lock_user(VERIFY_WRITE, arg0, sizeof(struct gdb_timeval), 0);
-            if (!p) {
-                result = -1;
-                errno = EFAULT;
-            } else {
-                result = 0;
-                p->tv_sec = cpu_to_be32(rt / G_USEC_PER_SEC);
-                p->tv_usec = cpu_to_be64(rt % G_USEC_PER_SEC);
-                unlock_user(p, arg0, sizeof(struct gdb_timeval));
-            }
-        }
+        GET_ARG(1);
+        semihost_sys_gettimeofday(cs, nios2_semi_u32_cb, arg0, arg1);
         break;
+
     case HOSTED_ISATTY:
         GET_ARG(0);
-        if (use_gdb_syscalls()) {
-            gdb_do_syscall(nios2_semi_u32_cb, "isatty,%x", arg0);
-            return;
-        } else {
-            result = isatty(arg0);
-        }
+        semihost_sys_isatty(cs, nios2_semi_u32_cb, arg0);
         break;
+
     case HOSTED_SYSTEM:
         GET_ARG(0);
         GET_ARG(1);
-        if (use_gdb_syscalls()) {
-            gdb_do_syscall(nios2_semi_u32_cb, "system,%s",
-                           arg0, (int)arg1);
-            return;
-        } else {
-            p = lock_user_string(arg0);
-            if (!p) {
-                result = -1;
-                errno = EFAULT;
-            } else {
-                result = system(p);
-                unlock_user(p, arg0, 0);
-            }
-        }
+        semihost_sys_system(cs, nios2_semi_u32_cb, arg0, arg1);
         break;
+
     default:
         qemu_log_mask(LOG_GUEST_ERROR, "nios2-semihosting: unsupported "
                       "semihosting syscall %d\n", nr);
-        result = 0;
+        nios2_semi_u32_cb(cs, -1, ENOSYS);
+        break;
+
+    failed:
+        nios2_semi_u32_cb(cs, -1, EFAULT);
+        break;
     }
-failed:
-    nios2_semi_u32_cb(cs, result, errno);
 }
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 54/74] target/mips: Use an exception for semihosting
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (52 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 53/74] target/nios2: Use semihosting/syscalls.h Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 55/74] target/mips: Add UHI errno values Richard Henderson
                   ` (19 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

Within do_interrupt, we hold the iothread lock, which
is required for Chardev access for the console, and for
the round trip for use_gdb_syscalls().

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/mips/cpu.h                         |  3 ++-
 target/mips/tcg/tcg-internal.h            |  2 ++
 target/mips/tcg/sysemu_helper.h.inc       |  2 --
 target/mips/tcg/exception.c               |  1 +
 target/mips/tcg/sysemu/mips-semi.c        |  4 ++--
 target/mips/tcg/sysemu/tlb_helper.c       |  4 ++++
 target/mips/tcg/translate.c               | 12 ++----------
 target/mips/tcg/micromips_translate.c.inc |  6 +++---
 target/mips/tcg/mips16e_translate.c.inc   |  2 +-
 target/mips/tcg/nanomips_translate.c.inc  |  4 ++--
 10 files changed, 19 insertions(+), 21 deletions(-)

diff --git a/target/mips/cpu.h b/target/mips/cpu.h
index 5335ac10a3..f56a5a95c4 100644
--- a/target/mips/cpu.h
+++ b/target/mips/cpu.h
@@ -1251,8 +1251,9 @@ enum {
     EXCP_MSAFPE,
     EXCP_TLBXI,
     EXCP_TLBRI,
+    EXCP_SEMIHOST,
 
-    EXCP_LAST = EXCP_TLBRI,
+    EXCP_LAST = EXCP_SEMIHOST,
 };
 
 /*
diff --git a/target/mips/tcg/tcg-internal.h b/target/mips/tcg/tcg-internal.h
index 993720b00c..1d27fa2ff9 100644
--- a/target/mips/tcg/tcg-internal.h
+++ b/target/mips/tcg/tcg-internal.h
@@ -62,6 +62,8 @@ bool mips_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
                        MMUAccessType access_type, int mmu_idx,
                        bool probe, uintptr_t retaddr);
 
+void mips_semihosting(CPUMIPSState *env);
+
 #endif /* !CONFIG_USER_ONLY */
 
 #endif
diff --git a/target/mips/tcg/sysemu_helper.h.inc b/target/mips/tcg/sysemu_helper.h.inc
index 4353a966f9..af585b5d9c 100644
--- a/target/mips/tcg/sysemu_helper.h.inc
+++ b/target/mips/tcg/sysemu_helper.h.inc
@@ -9,8 +9,6 @@
  * SPDX-License-Identifier: LGPL-2.1-or-later
  */
 
-DEF_HELPER_1(do_semihosting, void, env)
-
 /* CP0 helpers */
 DEF_HELPER_1(mfc0_mvpcontrol, tl, env)
 DEF_HELPER_1(mfc0_mvpconf0, tl, env)
diff --git a/target/mips/tcg/exception.c b/target/mips/tcg/exception.c
index 0b21e0872b..2bd77a61de 100644
--- a/target/mips/tcg/exception.c
+++ b/target/mips/tcg/exception.c
@@ -125,6 +125,7 @@ static const char * const excp_names[EXCP_LAST + 1] = {
     [EXCP_TLBRI] = "TLB read-inhibit",
     [EXCP_MSADIS] = "MSA disabled",
     [EXCP_MSAFPE] = "MSA floating point",
+    [EXCP_SEMIHOST] = "Semihosting",
 };
 
 const char *mips_exception_name(int32_t exception)
diff --git a/target/mips/tcg/sysemu/mips-semi.c b/target/mips/tcg/sysemu/mips-semi.c
index 6d6296e709..ac12c802a3 100644
--- a/target/mips/tcg/sysemu/mips-semi.c
+++ b/target/mips/tcg/sysemu/mips-semi.c
@@ -20,10 +20,10 @@
 #include "qemu/osdep.h"
 #include "cpu.h"
 #include "qemu/log.h"
-#include "exec/helper-proto.h"
 #include "semihosting/softmmu-uaccess.h"
 #include "semihosting/semihost.h"
 #include "semihosting/console.h"
+#include "internal.h"
 
 typedef enum UHIOp {
     UHI_exit = 1,
@@ -238,7 +238,7 @@ static int copy_argn_to_target(CPUMIPSState *env, int arg_num,
         unlock_user(p, gpr, 0);                 \
     } while (0)
 
-void helper_do_semihosting(CPUMIPSState *env)
+void mips_semihosting(CPUMIPSState *env)
 {
     target_ulong *gpr = env->active_tc.gpr;
     const UHIOp op = gpr[25];
diff --git a/target/mips/tcg/sysemu/tlb_helper.c b/target/mips/tcg/sysemu/tlb_helper.c
index 73254d1929..57ffad2902 100644
--- a/target/mips/tcg/sysemu/tlb_helper.c
+++ b/target/mips/tcg/sysemu/tlb_helper.c
@@ -1053,6 +1053,10 @@ void mips_cpu_do_interrupt(CPUState *cs)
     }
     offset = 0x180;
     switch (cs->exception_index) {
+    case EXCP_SEMIHOST:
+        cs->exception_index = EXCP_NONE;
+        mips_semihosting(env);
+        return;
     case EXCP_DSS:
         env->CP0_Debug |= 1 << CP0DB_DSS;
         /*
diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c
index 6de5b66650..e554b3adcc 100644
--- a/target/mips/tcg/translate.c
+++ b/target/mips/tcg/translate.c
@@ -12094,14 +12094,6 @@ static inline bool is_uhi(int sdbbp_code)
 #endif
 }
 
-#ifdef CONFIG_USER_ONLY
-/* The above should dead-code away any calls to this..*/
-static inline void gen_helper_do_semihosting(void *env)
-{
-    g_assert_not_reached();
-}
-#endif
-
 void gen_ldxs(DisasContext *ctx, int base, int index, int rd)
 {
     TCGv t0 = tcg_temp_new();
@@ -13910,7 +13902,7 @@ static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx)
         break;
     case R6_OPC_SDBBP:
         if (is_uhi(extract32(ctx->opcode, 6, 20))) {
-            gen_helper_do_semihosting(cpu_env);
+            generate_exception_end(ctx, EXCP_SEMIHOST);
         } else {
             if (ctx->hflags & MIPS_HFLAG_SBRI) {
                 gen_reserved_instruction(ctx);
@@ -14322,7 +14314,7 @@ static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx)
         break;
     case OPC_SDBBP:
         if (is_uhi(extract32(ctx->opcode, 6, 20))) {
-            gen_helper_do_semihosting(cpu_env);
+            generate_exception_end(ctx, EXCP_SEMIHOST);
         } else {
             /*
              * XXX: not clear which exception should be raised
diff --git a/target/mips/tcg/micromips_translate.c.inc b/target/mips/tcg/micromips_translate.c.inc
index fc6ede75b8..274caf2c3c 100644
--- a/target/mips/tcg/micromips_translate.c.inc
+++ b/target/mips/tcg/micromips_translate.c.inc
@@ -826,7 +826,7 @@ static void gen_pool16c_insn(DisasContext *ctx)
         break;
     case SDBBP16:
         if (is_uhi(extract32(ctx->opcode, 0, 4))) {
-            gen_helper_do_semihosting(cpu_env);
+            generate_exception_end(ctx, EXCP_SEMIHOST);
         } else {
             /*
              * XXX: not clear which exception should be raised
@@ -942,7 +942,7 @@ static void gen_pool16c_r6_insn(DisasContext *ctx)
         case R6_SDBBP16:
             /* SDBBP16 */
             if (is_uhi(extract32(ctx->opcode, 6, 4))) {
-                gen_helper_do_semihosting(cpu_env);
+                generate_exception_end(ctx, EXCP_SEMIHOST);
             } else {
                 if (ctx->hflags & MIPS_HFLAG_SBRI) {
                     generate_exception(ctx, EXCP_RI);
@@ -1311,7 +1311,7 @@ static void gen_pool32axf(CPUMIPSState *env, DisasContext *ctx, int rt, int rs)
             break;
         case SDBBP:
             if (is_uhi(extract32(ctx->opcode, 16, 10))) {
-                gen_helper_do_semihosting(cpu_env);
+                generate_exception_end(ctx, EXCP_SEMIHOST);
             } else {
                 check_insn(ctx, ISA_MIPS_R1);
                 if (ctx->hflags & MIPS_HFLAG_SBRI) {
diff --git a/target/mips/tcg/mips16e_translate.c.inc b/target/mips/tcg/mips16e_translate.c.inc
index f57e0a5f2a..0a3ba252e4 100644
--- a/target/mips/tcg/mips16e_translate.c.inc
+++ b/target/mips/tcg/mips16e_translate.c.inc
@@ -952,7 +952,7 @@ static int decode_ase_mips16e(CPUMIPSState *env, DisasContext *ctx)
             break;
         case RR_SDBBP:
             if (is_uhi(extract32(ctx->opcode, 5, 6))) {
-                gen_helper_do_semihosting(cpu_env);
+                generate_exception_end(ctx, EXCP_SEMIHOST);
             } else {
                 /*
                  * XXX: not clear which exception should be raised
diff --git a/target/mips/tcg/nanomips_translate.c.inc b/target/mips/tcg/nanomips_translate.c.inc
index 916cece4d2..5b0e4683a7 100644
--- a/target/mips/tcg/nanomips_translate.c.inc
+++ b/target/mips/tcg/nanomips_translate.c.inc
@@ -3691,7 +3691,7 @@ static int decode_nanomips_32_48_opc(CPUMIPSState *env, DisasContext *ctx)
                 break;
             case NM_SDBBP:
                 if (is_uhi(extract32(ctx->opcode, 0, 19))) {
-                    gen_helper_do_semihosting(cpu_env);
+                    generate_exception_end(ctx, EXCP_SEMIHOST);
                 } else {
                     if (ctx->hflags & MIPS_HFLAG_SBRI) {
                         gen_reserved_instruction(ctx);
@@ -4609,7 +4609,7 @@ static int decode_isa_nanomips(CPUMIPSState *env, DisasContext *ctx)
                 break;
             case NM_SDBBP16:
                 if (is_uhi(extract32(ctx->opcode, 0, 3))) {
-                    gen_helper_do_semihosting(cpu_env);
+                    generate_exception_end(ctx, EXCP_SEMIHOST);
                 } else {
                     if (ctx->hflags & MIPS_HFLAG_SBRI) {
                         gen_reserved_instruction(ctx);
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 55/74] target/mips: Add UHI errno values
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (53 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 54/74] target/mips: Use an exception for semihosting Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 56/74] target/mips: Create report_fault for semihosting Richard Henderson
                   ` (18 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

From the Unified Hosting Interface, MD01069 Reference Manual,
version 1.1.6, 06 July 2015.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/mips/tcg/sysemu/mips-semi.c | 40 ++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/target/mips/tcg/sysemu/mips-semi.c b/target/mips/tcg/sysemu/mips-semi.c
index ac12c802a3..2a039baf4c 100644
--- a/target/mips/tcg/sysemu/mips-semi.c
+++ b/target/mips/tcg/sysemu/mips-semi.c
@@ -74,6 +74,46 @@ enum UHIOpenFlags {
     UHIOpen_EXCL   = 0x800
 };
 
+enum UHIErrno {
+    UHI_EACCESS         = 13,
+    UHI_EAGAIN          = 11,
+    UHI_EBADF           = 9,
+    UHI_EBADMSG         = 77,
+    UHI_EBUSY           = 16,
+    UHI_ECONNRESET      = 104,
+    UHI_EEXIST          = 17,
+    UHI_EFBIG           = 27,
+    UHI_EINTR           = 4,
+    UHI_EINVAL          = 22,
+    UHI_EIO             = 5,
+    UHI_EISDIR          = 21,
+    UHI_ELOOP           = 92,
+    UHI_EMFILE          = 24,
+    UHI_EMLINK          = 31,
+    UHI_ENAMETOOLONG    = 91,
+    UHI_ENETDOWN        = 115,
+    UHI_ENETUNREACH     = 114,
+    UHI_ENFILE          = 23,
+    UHI_ENOBUFS         = 105,
+    UHI_ENOENT          = 2,
+    UHI_ENOMEM          = 12,
+    UHI_ENOSPC          = 28,
+    UHI_ENOSR           = 63,
+    UHI_ENOTCONN        = 128,
+    UHI_ENOTDIR         = 20,
+    UHI_ENXIO           = 6,
+    UHI_EOVERFLOW       = 139,
+    UHI_EPERM           = 1,
+    UHI_EPIPE           = 32,
+    UHI_ERANGE          = 34,
+    UHI_EROFS           = 30,
+    UHI_ESPIPE          = 29,
+    UHI_ETIMEDOUT       = 116,
+    UHI_ETXTBSY         = 26,
+    UHI_EWOULDBLOCK     = 11,
+    UHI_EXDEV           = 18,
+};
+
 static int errno_mips(int host_errno)
 {
     /* Errno values taken from asm-mips/errno.h */
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 56/74] target/mips: Create report_fault for semihosting
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (54 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 55/74] target/mips: Add UHI errno values Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 57/74] target/mips: Drop link syscall from semihosting Richard Henderson
                   ` (17 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

The UHI specification does not have an EFAULT value,
and further specifies that "undefined UHI operations
should not return control to the target".

So, log the error and abort.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/mips/tcg/sysemu/mips-semi.c | 33 ++++++++++++++----------------
 1 file changed, 15 insertions(+), 18 deletions(-)

diff --git a/target/mips/tcg/sysemu/mips-semi.c b/target/mips/tcg/sysemu/mips-semi.c
index 2a039baf4c..33221444e1 100644
--- a/target/mips/tcg/sysemu/mips-semi.c
+++ b/target/mips/tcg/sysemu/mips-semi.c
@@ -114,6 +114,13 @@ enum UHIErrno {
     UHI_EXDEV           = 18,
 };
 
+static void report_fault(CPUMIPSState *env)
+{
+    int op = env->active_tc.gpr[25];
+    error_report("Fault during UHI operation %d", op);
+    abort();
+}
+
 static int errno_mips(int host_errno)
 {
     /* Errno values taken from asm-mips/errno.h */
@@ -136,8 +143,7 @@ static int copy_stat_to_target(CPUMIPSState *env, const struct stat *src,
     hwaddr len = sizeof(struct UHIStat);
     UHIStat *dst = lock_user(VERIFY_WRITE, vaddr, len, 0);
     if (!dst) {
-        errno = EFAULT;
-        return -1;
+        report_fault(env);
     }
 
     dst->uhi_st_dev = tswap16(src->st_dev);
@@ -188,8 +194,7 @@ static int write_to_file(CPUMIPSState *env, target_ulong fd, target_ulong vaddr,
     int num_of_bytes;
     void *dst = lock_user(VERIFY_READ, vaddr, len, 1);
     if (!dst) {
-        errno = EFAULT;
-        return -1;
+        report_fault(env);
     }
 
     if (offset) {
@@ -213,8 +218,7 @@ static int read_from_file(CPUMIPSState *env, target_ulong fd,
     int num_of_bytes;
     void *dst = lock_user(VERIFY_WRITE, vaddr, len, 0);
     if (!dst) {
-        errno = EFAULT;
-        return -1;
+        report_fault(env);
     }
 
     if (offset) {
@@ -237,7 +241,7 @@ static int copy_argn_to_target(CPUMIPSState *env, int arg_num,
     int strsize = strlen(semihosting_get_arg(arg_num)) + 1;
     char *dst = lock_user(VERIFY_WRITE, vaddr, strsize, 0);
     if (!dst) {
-        return -1;
+        report_fault(env);
     }
 
     strcpy(dst, semihosting_get_arg(arg_num));
@@ -250,9 +254,7 @@ static int copy_argn_to_target(CPUMIPSState *env, int arg_num,
     do {                                        \
         p = lock_user_string(addr);             \
         if (!p) {                               \
-            gpr[2] = -1;                        \
-            gpr[3] = EFAULT;                    \
-            return;                             \
+            report_fault(env);                  \
         }                                       \
     } while (0)
 
@@ -260,16 +262,11 @@ static int copy_argn_to_target(CPUMIPSState *env, int arg_num,
     do {                                                \
         p = lock_user_string(addr);                     \
         if (!p) {                                       \
-            gpr[2] = -1;                                \
-            gpr[3] = EFAULT;                            \
-            return;                                     \
+            report_fault(env);                          \
         }                                               \
         p2 = lock_user_string(addr2);                   \
         if (!p2) {                                      \
-            unlock_user(p, addr, 0);                    \
-            gpr[2] = -1;                                \
-            gpr[3] = EFAULT;                            \
-            return;                                     \
+            report_fault(env);                          \
         }                                               \
     } while (0)
 
@@ -400,7 +397,7 @@ void mips_semihosting(CPUMIPSState *env)
         break;
 #endif
     default:
-        fprintf(stderr, "Unknown UHI operation %d\n", op);
+        error_report("Unknown UHI operation %d", op);
         abort();
     }
     return;
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 57/74] target/mips: Drop link syscall from semihosting
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (55 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 56/74] target/mips: Create report_fault for semihosting Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 58/74] target/mips: Drop pread and pwrite syscalls " Richard Henderson
                   ` (16 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

We don't implement it with _WIN32 hosts, and the syscall
is missing from the gdb remote file i/o interface.
Since we can't implement it universally, drop it.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/mips/tcg/sysemu/mips-semi.c | 9 ---------
 1 file changed, 9 deletions(-)

diff --git a/target/mips/tcg/sysemu/mips-semi.c b/target/mips/tcg/sysemu/mips-semi.c
index 33221444e1..254c7fad9a 100644
--- a/target/mips/tcg/sysemu/mips-semi.c
+++ b/target/mips/tcg/sysemu/mips-semi.c
@@ -387,15 +387,6 @@ void mips_semihosting(CPUMIPSState *env)
         gpr[2] = write_to_file(env, gpr[4], gpr[5], gpr[6], gpr[7]);
         gpr[3] = errno_mips(errno);
         break;
-#ifndef _WIN32
-    case UHI_link:
-        GET_TARGET_STRINGS_2(p, gpr[4], p2, gpr[5]);
-        gpr[2] = link(p, p2);
-        gpr[3] = errno_mips(errno);
-        FREE_TARGET_STRING(p2, gpr[5]);
-        FREE_TARGET_STRING(p, gpr[4]);
-        break;
-#endif
     default:
         error_report("Unknown UHI operation %d", op);
         abort();
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 58/74] target/mips: Drop pread and pwrite syscalls from semihosting
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (56 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 57/74] target/mips: Drop link syscall from semihosting Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 59/74] target/mips: Use semihosting/syscalls.h Richard Henderson
                   ` (15 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

We don't implement it with _WIN32 hosts, and the syscalls
are missing from the gdb remote file i/o interface.
Since we can't implement them universally, drop them.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/mips/tcg/sysemu/mips-semi.c | 39 ++++++------------------------
 1 file changed, 7 insertions(+), 32 deletions(-)

diff --git a/target/mips/tcg/sysemu/mips-semi.c b/target/mips/tcg/sysemu/mips-semi.c
index 254c7fad9a..93c9d3d0b3 100644
--- a/target/mips/tcg/sysemu/mips-semi.c
+++ b/target/mips/tcg/sysemu/mips-semi.c
@@ -188,8 +188,8 @@ static int get_open_flags(target_ulong target_flags)
     return open_flags;
 }
 
-static int write_to_file(CPUMIPSState *env, target_ulong fd, target_ulong vaddr,
-                         target_ulong len, target_ulong offset)
+static int write_to_file(CPUMIPSState *env, target_ulong fd,
+                         target_ulong vaddr, target_ulong len)
 {
     int num_of_bytes;
     void *dst = lock_user(VERIFY_READ, vaddr, len, 1);
@@ -197,23 +197,14 @@ static int write_to_file(CPUMIPSState *env, target_ulong fd, target_ulong vaddr,
         report_fault(env);
     }
 
-    if (offset) {
-#ifdef _WIN32
-        num_of_bytes = 0;
-#else
-        num_of_bytes = pwrite(fd, dst, len, offset);
-#endif
-    } else {
-        num_of_bytes = write(fd, dst, len);
-    }
+    num_of_bytes = write(fd, dst, len);
 
     unlock_user(dst, vaddr, 0);
     return num_of_bytes;
 }
 
 static int read_from_file(CPUMIPSState *env, target_ulong fd,
-                          target_ulong vaddr, target_ulong len,
-                          target_ulong offset)
+                          target_ulong vaddr, target_ulong len)
 {
     int num_of_bytes;
     void *dst = lock_user(VERIFY_WRITE, vaddr, len, 0);
@@ -221,15 +212,7 @@ static int read_from_file(CPUMIPSState *env, target_ulong fd,
         report_fault(env);
     }
 
-    if (offset) {
-#ifdef _WIN32
-        num_of_bytes = 0;
-#else
-        num_of_bytes = pread(fd, dst, len, offset);
-#endif
-    } else {
-        num_of_bytes = read(fd, dst, len);
-    }
+    num_of_bytes = read(fd, dst, len);
 
     unlock_user(dst, vaddr, len);
     return num_of_bytes;
@@ -309,11 +292,11 @@ void mips_semihosting(CPUMIPSState *env)
         gpr[3] = errno_mips(errno);
         break;
     case UHI_read:
-        gpr[2] = read_from_file(env, gpr[4], gpr[5], gpr[6], 0);
+        gpr[2] = read_from_file(env, gpr[4], gpr[5], gpr[6]);
         gpr[3] = errno_mips(errno);
         break;
     case UHI_write:
-        gpr[2] = write_to_file(env, gpr[4], gpr[5], gpr[6], 0);
+        gpr[2] = write_to_file(env, gpr[4], gpr[5], gpr[6]);
         gpr[3] = errno_mips(errno);
         break;
     case UHI_lseek:
@@ -379,14 +362,6 @@ void mips_semihosting(CPUMIPSState *env)
         FREE_TARGET_STRING(p, gpr[4]);
         abort();
         break;
-    case UHI_pread:
-        gpr[2] = read_from_file(env, gpr[4], gpr[5], gpr[6], gpr[7]);
-        gpr[3] = errno_mips(errno);
-        break;
-    case UHI_pwrite:
-        gpr[2] = write_to_file(env, gpr[4], gpr[5], gpr[6], gpr[7]);
-        gpr[3] = errno_mips(errno);
-        break;
     default:
         error_report("Unknown UHI operation %d", op);
         abort();
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 59/74] target/mips: Use semihosting/syscalls.h
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (57 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 58/74] target/mips: Drop pread and pwrite syscalls " Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 60/74] target/mips: Avoid qemu_semihosting_log_out for UHI_plog Richard Henderson
                   ` (14 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

This separates guest file descriptors from host file descriptors,
and utilizes shared infrastructure for integration with gdbstub.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/mips/tcg/sysemu/mips-semi.c | 219 +++++++++++++----------------
 1 file changed, 95 insertions(+), 124 deletions(-)

diff --git a/target/mips/tcg/sysemu/mips-semi.c b/target/mips/tcg/sysemu/mips-semi.c
index 93c9d3d0b3..2704177a95 100644
--- a/target/mips/tcg/sysemu/mips-semi.c
+++ b/target/mips/tcg/sysemu/mips-semi.c
@@ -20,9 +20,11 @@
 #include "qemu/osdep.h"
 #include "cpu.h"
 #include "qemu/log.h"
+#include "exec/gdbstub.h"
 #include "semihosting/softmmu-uaccess.h"
 #include "semihosting/semihost.h"
 #include "semihosting/console.h"
+#include "semihosting/syscalls.h"
 #include "internal.h"
 
 typedef enum UHIOp {
@@ -121,101 +123,79 @@ static void report_fault(CPUMIPSState *env)
     abort();
 }
 
-static int errno_mips(int host_errno)
+static void uhi_cb(CPUState *cs, uint64_t ret, int err)
 {
-    /* Errno values taken from asm-mips/errno.h */
-    switch (host_errno) {
-    case 0:             return 0;
-    case ENAMETOOLONG:  return 78;
-#ifdef EOVERFLOW
-    case EOVERFLOW:     return 79;
-#endif
-#ifdef ELOOP
-    case ELOOP:         return 90;
-#endif
-    default:            return EINVAL;
-    }
-}
+    CPUMIPSState *env = cs->env_ptr;
 
-static int copy_stat_to_target(CPUMIPSState *env, const struct stat *src,
-                               target_ulong vaddr)
-{
-    hwaddr len = sizeof(struct UHIStat);
-    UHIStat *dst = lock_user(VERIFY_WRITE, vaddr, len, 0);
-    if (!dst) {
+#define E(N) case E##N: err = UHI_E##N; break
+
+    switch (err) {
+    E(PERM);
+    E(NOENT);
+    E(INTR);
+    E(BADF);
+    E(BUSY);
+    E(EXIST);
+    E(NOTDIR);
+    E(ISDIR);
+    E(INVAL);
+    E(NFILE);
+    E(MFILE);
+    E(FBIG);
+    E(NOSPC);
+    E(SPIPE);
+    E(ROFS);
+    E(NAMETOOLONG);
+    case 0:
+        break;
+    default:
+        err = UHI_EINVAL;
+        break;
+    case GDB_EFAULT:
         report_fault(env);
     }
 
-    dst->uhi_st_dev = tswap16(src->st_dev);
-    dst->uhi_st_ino = tswap16(src->st_ino);
-    dst->uhi_st_mode = tswap32(src->st_mode);
-    dst->uhi_st_nlink = tswap16(src->st_nlink);
-    dst->uhi_st_uid = tswap16(src->st_uid);
-    dst->uhi_st_gid = tswap16(src->st_gid);
-    dst->uhi_st_rdev = tswap16(src->st_rdev);
-    dst->uhi_st_size = tswap64(src->st_size);
-    dst->uhi_st_atime = tswap64(src->st_atime);
-    dst->uhi_st_mtime = tswap64(src->st_mtime);
-    dst->uhi_st_ctime = tswap64(src->st_ctime);
-#ifdef _WIN32
-    dst->uhi_st_blksize = 0;
-    dst->uhi_st_blocks = 0;
-#else
-    dst->uhi_st_blksize = tswap64(src->st_blksize);
-    dst->uhi_st_blocks = tswap64(src->st_blocks);
-#endif
-    unlock_user(dst, vaddr, len);
-    return 0;
+#undef E
+
+    env->active_tc.gpr[2] = ret;
+    env->active_tc.gpr[3] = err;
 }
 
-static int get_open_flags(target_ulong target_flags)
+static void uhi_fstat_cb(CPUState *cs, uint64_t ret, int err)
 {
-    int open_flags = 0;
+    QEMU_BUILD_BUG_ON(sizeof(UHIStat) < sizeof(struct gdb_stat));
 
-    if (target_flags & UHIOpen_RDWR) {
-        open_flags |= O_RDWR;
-    } else if (target_flags & UHIOpen_WRONLY) {
-        open_flags |= O_WRONLY;
-    } else {
-        open_flags |= O_RDONLY;
+    if (!err) {
+        CPUMIPSState *env = cs->env_ptr;
+        target_ulong addr = env->active_tc.gpr[5];
+        UHIStat *dst = lock_user(VERIFY_WRITE, addr, sizeof(UHIStat), 1);
+        struct gdb_stat s;
+
+        if (!dst) {
+            report_fault(env);
+        }
+
+        memcpy(&s, dst, sizeof(struct gdb_stat));
+        memset(dst, 0, sizeof(UHIStat));
+
+        dst->uhi_st_dev = tswap16(be32_to_cpu(s.gdb_st_dev));
+        dst->uhi_st_ino = tswap16(be32_to_cpu(s.gdb_st_ino));
+        dst->uhi_st_mode = tswap32(be32_to_cpu(s.gdb_st_mode));
+        dst->uhi_st_nlink = tswap16(be32_to_cpu(s.gdb_st_nlink));
+        dst->uhi_st_uid = tswap16(be32_to_cpu(s.gdb_st_uid));
+        dst->uhi_st_gid = tswap16(be32_to_cpu(s.gdb_st_gid));
+        dst->uhi_st_rdev = tswap16(be32_to_cpu(s.gdb_st_rdev));
+        dst->uhi_st_size = tswap64(be64_to_cpu(s.gdb_st_size));
+        dst->uhi_st_atime = tswap64(be32_to_cpu(s.gdb_st_atime));
+        dst->uhi_st_mtime = tswap64(be32_to_cpu(s.gdb_st_mtime));
+        dst->uhi_st_ctime = tswap64(be32_to_cpu(s.gdb_st_ctime));
+        dst->uhi_st_blksize = tswap64(be64_to_cpu(s.gdb_st_blksize));
+        dst->uhi_st_blocks = tswap64(be64_to_cpu(s.gdb_st_blocks));
+
+        unlock_user(dst, addr, sizeof(UHIStat));
     }
 
-    open_flags |= (target_flags & UHIOpen_APPEND) ? O_APPEND : 0;
-    open_flags |= (target_flags & UHIOpen_CREAT)  ? O_CREAT  : 0;
-    open_flags |= (target_flags & UHIOpen_TRUNC)  ? O_TRUNC  : 0;
-    open_flags |= (target_flags & UHIOpen_EXCL)   ? O_EXCL   : 0;
-
-    return open_flags;
-}
-
-static int write_to_file(CPUMIPSState *env, target_ulong fd,
-                         target_ulong vaddr, target_ulong len)
-{
-    int num_of_bytes;
-    void *dst = lock_user(VERIFY_READ, vaddr, len, 1);
-    if (!dst) {
-        report_fault(env);
-    }
-
-    num_of_bytes = write(fd, dst, len);
-
-    unlock_user(dst, vaddr, 0);
-    return num_of_bytes;
-}
-
-static int read_from_file(CPUMIPSState *env, target_ulong fd,
-                          target_ulong vaddr, target_ulong len)
-{
-    int num_of_bytes;
-    void *dst = lock_user(VERIFY_WRITE, vaddr, len, 0);
-    if (!dst) {
-        report_fault(env);
-    }
-
-    num_of_bytes = read(fd, dst, len);
-
-    unlock_user(dst, vaddr, len);
-    return num_of_bytes;
+    uhi_cb(cs, ret, err);
 }
 
 static int copy_argn_to_target(CPUMIPSState *env, int arg_num,
@@ -260,68 +240,59 @@ static int copy_argn_to_target(CPUMIPSState *env, int arg_num,
 
 void mips_semihosting(CPUMIPSState *env)
 {
+    CPUState *cs = env_cpu(env);
     target_ulong *gpr = env->active_tc.gpr;
     const UHIOp op = gpr[25];
     char *p, *p2;
 
     switch (op) {
     case UHI_exit:
-        qemu_log("UHI(%d): exit(%d)\n", op, (int)gpr[4]);
+        gdb_exit(gpr[4]);
         exit(gpr[4]);
+
     case UHI_open:
-        GET_TARGET_STRING(p, gpr[4]);
-        if (!strcmp("/dev/stdin", p)) {
-            gpr[2] = 0;
-        } else if (!strcmp("/dev/stdout", p)) {
-            gpr[2] = 1;
-        } else if (!strcmp("/dev/stderr", p)) {
-            gpr[2] = 2;
-        } else {
-            gpr[2] = open(p, get_open_flags(gpr[5]), gpr[6]);
-            gpr[3] = errno_mips(errno);
+        {
+            int ret = -1;
+
+            GET_TARGET_STRING(p, gpr[4]);
+            if (!strcmp("/dev/stdin", p)) {
+                ret = 0;
+            } else if (!strcmp("/dev/stdout", p)) {
+                ret = 1;
+            } else if (!strcmp("/dev/stderr", p)) {
+                ret = 2;
+            }
+            FREE_TARGET_STRING(p, gpr[4]);
+
+            /* FIXME: reusing a guest fd doesn't seem correct. */
+            if (ret >= 0) {
+                gpr[2] = ret;
+                break;
+            }
+
+            semihost_sys_open(cs, uhi_cb, gpr[4], 0, gpr[5], gpr[6]);
         }
-        FREE_TARGET_STRING(p, gpr[4]);
         break;
+
     case UHI_close:
-        if (gpr[4] < 3) {
-            /* ignore closing stdin/stdout/stderr */
-            gpr[2] = 0;
-            return;
-        }
-        gpr[2] = close(gpr[4]);
-        gpr[3] = errno_mips(errno);
+        semihost_sys_close(cs, uhi_cb, gpr[4]);
         break;
     case UHI_read:
-        gpr[2] = read_from_file(env, gpr[4], gpr[5], gpr[6]);
-        gpr[3] = errno_mips(errno);
+        semihost_sys_read(cs, uhi_cb, gpr[4], gpr[5], gpr[6]);
         break;
     case UHI_write:
-        gpr[2] = write_to_file(env, gpr[4], gpr[5], gpr[6]);
-        gpr[3] = errno_mips(errno);
+        semihost_sys_write(cs, uhi_cb, gpr[4], gpr[5], gpr[6]);
         break;
     case UHI_lseek:
-        gpr[2] = lseek(gpr[4], gpr[5], gpr[6]);
-        gpr[3] = errno_mips(errno);
+        semihost_sys_lseek(cs, uhi_cb, gpr[4], gpr[5], gpr[6]);
         break;
     case UHI_unlink:
-        GET_TARGET_STRING(p, gpr[4]);
-        gpr[2] = remove(p);
-        gpr[3] = errno_mips(errno);
-        FREE_TARGET_STRING(p, gpr[4]);
+        semihost_sys_remove(cs, uhi_cb, gpr[4], 0);
         break;
     case UHI_fstat:
-        {
-            struct stat sbuf;
-            memset(&sbuf, 0, sizeof(sbuf));
-            gpr[2] = fstat(gpr[4], &sbuf);
-            gpr[3] = errno_mips(errno);
-            if (gpr[2]) {
-                return;
-            }
-            gpr[2] = copy_stat_to_target(env, &sbuf, gpr[5]);
-            gpr[3] = errno_mips(errno);
-        }
+        semihost_sys_fstat(cs, uhi_fstat_cb, gpr[4], gpr[5]);
         break;
+
     case UHI_argc:
         gpr[2] = semihosting_get_argc();
         break;
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 60/74] target/mips: Avoid qemu_semihosting_log_out for UHI_plog
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (58 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 59/74] target/mips: Use semihosting/syscalls.h Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 61/74] target/mips: Use error_report for UHI_assert Richard Henderson
                   ` (13 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

Use semihost_sys_write and/or qemu_semihosting_console_write
for implementing plog.  When using gdbstub, copy the temp
string below the stack so that gdb has a guest address from
which to perform the log.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/mips/tcg/sysemu/mips-semi.c | 52 +++++++++++++++++++++++-------
 1 file changed, 41 insertions(+), 11 deletions(-)

diff --git a/target/mips/tcg/sysemu/mips-semi.c b/target/mips/tcg/sysemu/mips-semi.c
index 2704177a95..d8c9be5e9f 100644
--- a/target/mips/tcg/sysemu/mips-semi.c
+++ b/target/mips/tcg/sysemu/mips-semi.c
@@ -310,20 +310,50 @@ void mips_semihosting(CPUMIPSState *env)
         }
         gpr[2] = copy_argn_to_target(env, gpr[4], gpr[5]);
         break;
+
     case UHI_plog:
-        GET_TARGET_STRING(p, gpr[4]);
-        p2 = strstr(p, "%d");
-        if (p2) {
-            int char_num = p2 - p;
-            GString *s = g_string_new_len(p, char_num);
-            g_string_append_printf(s, "%d%s", (int)gpr[5], p2 + 2);
-            gpr[2] = qemu_semihosting_log_out(s->str, s->len);
-            g_string_free(s, true);
-        } else {
-            gpr[2] = qemu_semihosting_log_out(p, strlen(p));
+        {
+            target_ulong addr = gpr[4];
+            ssize_t len = target_strlen(addr);
+            GString *str;
+            char *pct_d;
+
+            if (len < 0) {
+                report_fault(env);
+            }
+            p = lock_user(VERIFY_READ, addr, len, 1);
+            if (!p) {
+                report_fault(env);
+            }
+
+            pct_d = strstr(p, "%d");
+            if (!pct_d) {
+                FREE_TARGET_STRING(p, addr);
+                semihost_sys_write(cs, uhi_cb, 2, addr, len);
+                break;
+            }
+
+            str = g_string_new_len(p, pct_d - p);
+            g_string_append_printf(str, "%d%s", (int)gpr[5], pct_d + 2);
+            FREE_TARGET_STRING(p, addr);
+
+            /*
+             * When we're using gdb, we need a guest address, so
+             * drop the string onto the stack below the stack pointer.
+             */
+            if (use_gdb_syscalls()) {
+                addr = gpr[29] - str->len;
+                p = lock_user(VERIFY_WRITE, addr, str->len, 0);
+                memcpy(p, str->str, str->len);
+                unlock_user(p, addr, str->len);
+                semihost_sys_write(cs, uhi_cb, 2, addr, str->len);
+            } else {
+                gpr[2] = qemu_semihosting_console_write(str->str, str->len);
+            }
+            g_string_free(str, true);
         }
-        FREE_TARGET_STRING(p, gpr[4]);
         break;
+
     case UHI_assert:
         GET_TARGET_STRINGS_2(p, gpr[4], p2, gpr[5]);
         printf("assertion '");
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 61/74] target/mips: Use error_report for UHI_assert
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (59 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 60/74] target/mips: Avoid qemu_semihosting_log_out for UHI_plog Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 62/74] semihosting: Remove qemu_semihosting_log_out Richard Henderson
                   ` (12 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

Always log the assert locally.  Do not report_fault, but
instead include the fact of the fault in the assertion.
Don't bother freeing allocated strings before the abort().

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/mips/tcg/sysemu/mips-semi.c | 39 ++++++++++++++----------------
 1 file changed, 18 insertions(+), 21 deletions(-)

diff --git a/target/mips/tcg/sysemu/mips-semi.c b/target/mips/tcg/sysemu/mips-semi.c
index d8c9be5e9f..df1747aafe 100644
--- a/target/mips/tcg/sysemu/mips-semi.c
+++ b/target/mips/tcg/sysemu/mips-semi.c
@@ -221,18 +221,6 @@ static int copy_argn_to_target(CPUMIPSState *env, int arg_num,
         }                                       \
     } while (0)
 
-#define GET_TARGET_STRINGS_2(p, addr, p2, addr2)        \
-    do {                                                \
-        p = lock_user_string(addr);                     \
-        if (!p) {                                       \
-            report_fault(env);                          \
-        }                                               \
-        p2 = lock_user_string(addr2);                   \
-        if (!p2) {                                      \
-            report_fault(env);                          \
-        }                                               \
-    } while (0)
-
 #define FREE_TARGET_STRING(p, gpr)              \
     do {                                        \
         unlock_user(p, gpr, 0);                 \
@@ -243,7 +231,7 @@ void mips_semihosting(CPUMIPSState *env)
     CPUState *cs = env_cpu(env);
     target_ulong *gpr = env->active_tc.gpr;
     const UHIOp op = gpr[25];
-    char *p, *p2;
+    char *p;
 
     switch (op) {
     case UHI_exit:
@@ -355,14 +343,23 @@ void mips_semihosting(CPUMIPSState *env)
         break;
 
     case UHI_assert:
-        GET_TARGET_STRINGS_2(p, gpr[4], p2, gpr[5]);
-        printf("assertion '");
-        printf("\"%s\"", p);
-        printf("': file \"%s\", line %d\n", p2, (int)gpr[6]);
-        FREE_TARGET_STRING(p2, gpr[5]);
-        FREE_TARGET_STRING(p, gpr[4]);
-        abort();
-        break;
+        {
+            const char *msg, *file;
+
+            msg = lock_user_string(gpr[4]);
+            if (!msg) {
+                msg = "<EFAULT>";
+            }
+            file = lock_user_string(gpr[5]);
+            if (!file) {
+                file = "<EFAULT>";
+            }
+
+            error_report("UHI assertion \"%s\": file \"%s\", line %d",
+                         msg, file, (int)gpr[6]);
+            abort();
+        }
+
     default:
         error_report("Unknown UHI operation %d", op);
         abort();
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 62/74] semihosting: Remove qemu_semihosting_log_out
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (60 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 61/74] target/mips: Use error_report for UHI_assert Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 63/74] target/mips: Simplify UHI_argnlen and UHI_argn Richard Henderson
                   ` (11 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

The function is no longer used.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/semihosting/console.h | 13 -------------
 semihosting/console.c         |  9 ---------
 2 files changed, 22 deletions(-)

diff --git a/include/semihosting/console.h b/include/semihosting/console.h
index 61b0cb3a94..bd78e5f03f 100644
--- a/include/semihosting/console.h
+++ b/include/semihosting/console.h
@@ -40,19 +40,6 @@ int qemu_semihosting_console_read(CPUState *cs, void *buf, int len);
  */
 int qemu_semihosting_console_write(void *buf, int len);
 
-/**
- * qemu_semihosting_log_out:
- * @s: pointer to string
- * @len: length of string
- *
- * Send a string to the debug output. Unlike console_out these strings
- * can't be sent to a remote gdb instance as they don't exist in guest
- * memory.
- *
- * Returns: number of bytes written
- */
-int qemu_semihosting_log_out(const char *s, int len);
-
 /*
  * qemu_semihosting_console_block_until_ready:
  * @cs: CPUState
diff --git a/semihosting/console.c b/semihosting/console.c
index cda7cf1905..5b1ec0a1c3 100644
--- a/semihosting/console.c
+++ b/semihosting/console.c
@@ -38,15 +38,6 @@ typedef struct SemihostingConsole {
 
 static SemihostingConsole console;
 
-int qemu_semihosting_log_out(const char *s, int len)
-{
-    if (console.chr) {
-        return qemu_chr_write_all(console.chr, (uint8_t *) s, len);
-    } else {
-        return write(STDERR_FILENO, s, len);
-    }
-}
-
 #define FIFO_SIZE   1024
 
 static int console_can_read(void *opaque)
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 63/74] target/mips: Simplify UHI_argnlen and UHI_argn
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (61 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 62/74] semihosting: Remove qemu_semihosting_log_out Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 64/74] target/mips: Remove GET_TARGET_STRING and FREE_TARGET_STRING Richard Henderson
                   ` (10 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

With semihosting_get_arg, we already have a check vs argc, so
there's no point replicating it -- just check the result vs NULL.
Merge copy_argn_to_target into its caller.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/mips/tcg/sysemu/mips-semi.c | 44 ++++++++++++++----------------
 1 file changed, 21 insertions(+), 23 deletions(-)

diff --git a/target/mips/tcg/sysemu/mips-semi.c b/target/mips/tcg/sysemu/mips-semi.c
index df1747aafe..0f5b509ce2 100644
--- a/target/mips/tcg/sysemu/mips-semi.c
+++ b/target/mips/tcg/sysemu/mips-semi.c
@@ -198,21 +198,6 @@ static void uhi_fstat_cb(CPUState *cs, uint64_t ret, int err)
     uhi_cb(cs, ret, err);
 }
 
-static int copy_argn_to_target(CPUMIPSState *env, int arg_num,
-                               target_ulong vaddr)
-{
-    int strsize = strlen(semihosting_get_arg(arg_num)) + 1;
-    char *dst = lock_user(VERIFY_WRITE, vaddr, strsize, 0);
-    if (!dst) {
-        report_fault(env);
-    }
-
-    strcpy(dst, semihosting_get_arg(arg_num));
-
-    unlock_user(dst, vaddr, strsize);
-    return 0;
-}
-
 #define GET_TARGET_STRING(p, addr)              \
     do {                                        \
         p = lock_user_string(addr);             \
@@ -285,18 +270,31 @@ void mips_semihosting(CPUMIPSState *env)
         gpr[2] = semihosting_get_argc();
         break;
     case UHI_argnlen:
-        if (gpr[4] >= semihosting_get_argc()) {
-            gpr[2] = -1;
-            return;
+        {
+            const char *s = semihosting_get_arg(gpr[4]);
+            gpr[2] = s ? strlen(s) : -1;
         }
-        gpr[2] = strlen(semihosting_get_arg(gpr[4]));
         break;
     case UHI_argn:
-        if (gpr[4] >= semihosting_get_argc()) {
-            gpr[2] = -1;
-            return;
+        {
+            const char *s = semihosting_get_arg(gpr[4]);
+            target_ulong addr;
+            size_t len;
+
+            if (!s) {
+                gpr[2] = -1;
+                break;
+            }
+            len = strlen(s) + 1;
+            addr = gpr[5];
+            p = lock_user(VERIFY_WRITE, addr, len, 0);
+            if (!p) {
+                report_fault(env);
+            }
+            memcpy(p, s, len);
+            unlock_user(p, addr, len);
+            gpr[2] = 0;
         }
-        gpr[2] = copy_argn_to_target(env, gpr[4], gpr[5]);
         break;
 
     case UHI_plog:
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 64/74] target/mips: Remove GET_TARGET_STRING and FREE_TARGET_STRING
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (62 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 63/74] target/mips: Simplify UHI_argnlen and UHI_argn Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 65/74] target/xtensa: Use an exception for semihosting Richard Henderson
                   ` (9 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

Inline these macros into the only two callers.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/mips/tcg/sysemu/mips-semi.c | 27 +++++++++------------------
 1 file changed, 9 insertions(+), 18 deletions(-)

diff --git a/target/mips/tcg/sysemu/mips-semi.c b/target/mips/tcg/sysemu/mips-semi.c
index 0f5b509ce2..a3d5267399 100644
--- a/target/mips/tcg/sysemu/mips-semi.c
+++ b/target/mips/tcg/sysemu/mips-semi.c
@@ -198,19 +198,6 @@ static void uhi_fstat_cb(CPUState *cs, uint64_t ret, int err)
     uhi_cb(cs, ret, err);
 }
 
-#define GET_TARGET_STRING(p, addr)              \
-    do {                                        \
-        p = lock_user_string(addr);             \
-        if (!p) {                               \
-            report_fault(env);                  \
-        }                                       \
-    } while (0)
-
-#define FREE_TARGET_STRING(p, gpr)              \
-    do {                                        \
-        unlock_user(p, gpr, 0);                 \
-    } while (0)
-
 void mips_semihosting(CPUMIPSState *env)
 {
     CPUState *cs = env_cpu(env);
@@ -225,9 +212,13 @@ void mips_semihosting(CPUMIPSState *env)
 
     case UHI_open:
         {
+            target_ulong fname = gpr[4];
             int ret = -1;
 
-            GET_TARGET_STRING(p, gpr[4]);
+            p = lock_user_string(fname);
+            if (!p) {
+                report_fault(env);
+            }
             if (!strcmp("/dev/stdin", p)) {
                 ret = 0;
             } else if (!strcmp("/dev/stdout", p)) {
@@ -235,7 +226,7 @@ void mips_semihosting(CPUMIPSState *env)
             } else if (!strcmp("/dev/stderr", p)) {
                 ret = 2;
             }
-            FREE_TARGET_STRING(p, gpr[4]);
+            unlock_user(p, fname, 0);
 
             /* FIXME: reusing a guest fd doesn't seem correct. */
             if (ret >= 0) {
@@ -243,7 +234,7 @@ void mips_semihosting(CPUMIPSState *env)
                 break;
             }
 
-            semihost_sys_open(cs, uhi_cb, gpr[4], 0, gpr[5], gpr[6]);
+            semihost_sys_open(cs, uhi_cb, fname, 0, gpr[5], gpr[6]);
         }
         break;
 
@@ -314,14 +305,14 @@ void mips_semihosting(CPUMIPSState *env)
 
             pct_d = strstr(p, "%d");
             if (!pct_d) {
-                FREE_TARGET_STRING(p, addr);
+                unlock_user(p, addr, 0);
                 semihost_sys_write(cs, uhi_cb, 2, addr, len);
                 break;
             }
 
             str = g_string_new_len(p, pct_d - p);
             g_string_append_printf(str, "%d%s", (int)gpr[5], pct_d + 2);
-            FREE_TARGET_STRING(p, addr);
+            unlock_user(p, addr, 0);
 
             /*
              * When we're using gdb, we need a guest address, so
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 65/74] target/xtensa: Use an exception for semihosting
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (63 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 64/74] target/mips: Remove GET_TARGET_STRING and FREE_TARGET_STRING Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 66/74] target/xtensa: Use semihosting/syscalls.h Richard Henderson
                   ` (8 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

Within do_interrupt, we hold the iothread lock, which
is required for Chardev access for the console, and for
the round trip for use_gdb_syscalls().

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/xtensa/cpu.h         | 2 ++
 target/xtensa/helper.h      | 3 ---
 target/xtensa/exc_helper.c  | 4 ++++
 target/xtensa/translate.c   | 3 ++-
 target/xtensa/xtensa-semi.c | 3 +--
 5 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h
index d4b8268146..411a128f60 100644
--- a/target/xtensa/cpu.h
+++ b/target/xtensa/cpu.h
@@ -259,6 +259,7 @@ enum {
     EXC_USER,
     EXC_DOUBLE,
     EXC_DEBUG,
+    EXC_SEMIHOST,
     EXC_MAX
 };
 
@@ -574,6 +575,7 @@ void xtensa_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr,
                                       unsigned size, MMUAccessType access_type,
                                       int mmu_idx, MemTxAttrs attrs,
                                       MemTxResult response, uintptr_t retaddr);
+void xtensa_semihosting(CPUXtensaState *env);
 #endif
 void xtensa_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
 hwaddr xtensa_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
diff --git a/target/xtensa/helper.h b/target/xtensa/helper.h
index ae938ceedb..531679cd86 100644
--- a/target/xtensa/helper.h
+++ b/target/xtensa/helper.h
@@ -11,9 +11,6 @@ DEF_HELPER_2(retw, void, env, i32)
 DEF_HELPER_3(window_check, noreturn, env, i32, i32)
 DEF_HELPER_1(restore_owb, void, env)
 DEF_HELPER_2(movsp, void, env, i32)
-#ifndef CONFIG_USER_ONLY
-DEF_HELPER_1(simcall, void, env)
-#endif
 
 #ifndef CONFIG_USER_ONLY
 DEF_HELPER_3(waiti, void, env, i32, i32)
diff --git a/target/xtensa/exc_helper.c b/target/xtensa/exc_helper.c
index d4823a65cd..d54a518875 100644
--- a/target/xtensa/exc_helper.c
+++ b/target/xtensa/exc_helper.c
@@ -219,6 +219,10 @@ void xtensa_cpu_do_interrupt(CPUState *cs)
     }
 
     switch (cs->exception_index) {
+    case EXC_SEMIHOST:
+        xtensa_semihosting(env);
+        return;
+
     case EXC_WINDOW_OVERFLOW4:
     case EXC_WINDOW_UNDERFLOW4:
     case EXC_WINDOW_OVERFLOW8:
diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c
index 1485df2f22..6ddb2e112e 100644
--- a/target/xtensa/translate.c
+++ b/target/xtensa/translate.c
@@ -2416,7 +2416,8 @@ static void translate_simcall(DisasContext *dc, const OpcodeArg arg[],
 {
 #ifndef CONFIG_USER_ONLY
     if (semihosting_enabled()) {
-        gen_helper_simcall(cpu_env);
+        tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
+        gen_exception(dc, EXC_SEMIHOST);
     }
 #endif
 }
diff --git a/target/xtensa/xtensa-semi.c b/target/xtensa/xtensa-semi.c
index fa21b7e11f..5375f106fc 100644
--- a/target/xtensa/xtensa-semi.c
+++ b/target/xtensa/xtensa-semi.c
@@ -28,7 +28,6 @@
 #include "qemu/osdep.h"
 #include "cpu.h"
 #include "chardev/char-fe.h"
-#include "exec/helper-proto.h"
 #include "semihosting/semihost.h"
 #include "qapi/error.h"
 #include "qemu/log.h"
@@ -188,7 +187,7 @@ void xtensa_sim_open_console(Chardev *chr)
     sim_console = &console;
 }
 
-void HELPER(simcall)(CPUXtensaState *env)
+void xtensa_semihosting(CPUXtensaState *env)
 {
     CPUState *cs = env_cpu(env);
     uint32_t *regs = env->regs;
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 66/74] target/xtensa: Use semihosting/syscalls.h
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (64 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 65/74] target/xtensa: Use an exception for semihosting Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 67/74] tests/docker: Add debian-rx-cross image Richard Henderson
                   ` (7 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

This separates guest file descriptors from host file descriptors,
and utilizes shared infrastructure for integration with gdbstub.
Remove the xtensa custom console handing and rely on the
generic -semihosting-config handling of chardevs.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/xtensa/cpu.h         |   1 -
 hw/xtensa/sim.c             |   3 -
 target/xtensa/xtensa-semi.c | 303 +++++++++---------------------------
 3 files changed, 77 insertions(+), 230 deletions(-)

diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h
index 411a128f60..b1311a0530 100644
--- a/target/xtensa/cpu.h
+++ b/target/xtensa/cpu.h
@@ -610,7 +610,6 @@ void xtensa_translate_init(void);
 void **xtensa_get_regfile_by_name(const char *name, int entries, int bits);
 void xtensa_breakpoint_handler(CPUState *cs);
 void xtensa_register_core(XtensaConfigList *node);
-void xtensa_sim_open_console(Chardev *chr);
 void check_interrupts(CPUXtensaState *s);
 void xtensa_irq_init(CPUXtensaState *env);
 qemu_irq *xtensa_get_extints(CPUXtensaState *env);
diff --git a/hw/xtensa/sim.c b/hw/xtensa/sim.c
index 946c71cb5b..5cca6a170e 100644
--- a/hw/xtensa/sim.c
+++ b/hw/xtensa/sim.c
@@ -87,9 +87,6 @@ XtensaCPU *xtensa_sim_common_init(MachineState *machine)
         xtensa_create_memory_regions(&sysram, "xtensa.sysram",
                                      get_system_memory());
     }
-    if (serial_hd(0)) {
-        xtensa_sim_open_console(serial_hd(0));
-    }
     return cpu;
 }
 
diff --git a/target/xtensa/xtensa-semi.c b/target/xtensa/xtensa-semi.c
index 5375f106fc..42baae419b 100644
--- a/target/xtensa/xtensa-semi.c
+++ b/target/xtensa/xtensa-semi.c
@@ -27,8 +27,10 @@
 
 #include "qemu/osdep.h"
 #include "cpu.h"
-#include "chardev/char-fe.h"
+#include "exec/gdbstub.h"
 #include "semihosting/semihost.h"
+#include "semihosting/syscalls.h"
+#include "semihosting/softmmu-uaccess.h"
 #include "qapi/error.h"
 #include "qemu/log.h"
 
@@ -92,99 +94,49 @@ enum {
     TARGET_ELOOP        = 92,
 };
 
-static uint32_t errno_h2g(int host_errno)
+static void xtensa_cb(CPUState *cs, uint64_t ret, int err)
 {
-    switch (host_errno) {
-    case 0:         return 0;
-    case EPERM:     return TARGET_EPERM;
-    case ENOENT:    return TARGET_ENOENT;
-    case ESRCH:     return TARGET_ESRCH;
-    case EINTR:     return TARGET_EINTR;
-    case EIO:       return TARGET_EIO;
-    case ENXIO:     return TARGET_ENXIO;
-    case E2BIG:     return TARGET_E2BIG;
-    case ENOEXEC:   return TARGET_ENOEXEC;
-    case EBADF:     return TARGET_EBADF;
-    case ECHILD:    return TARGET_ECHILD;
-    case EAGAIN:    return TARGET_EAGAIN;
-    case ENOMEM:    return TARGET_ENOMEM;
-    case EACCES:    return TARGET_EACCES;
-    case EFAULT:    return TARGET_EFAULT;
-#ifdef ENOTBLK
-    case ENOTBLK:   return TARGET_ENOTBLK;
-#endif
-    case EBUSY:     return TARGET_EBUSY;
-    case EEXIST:    return TARGET_EEXIST;
-    case EXDEV:     return TARGET_EXDEV;
-    case ENODEV:    return TARGET_ENODEV;
-    case ENOTDIR:   return TARGET_ENOTDIR;
-    case EISDIR:    return TARGET_EISDIR;
-    case EINVAL:    return TARGET_EINVAL;
-    case ENFILE:    return TARGET_ENFILE;
-    case EMFILE:    return TARGET_EMFILE;
-    case ENOTTY:    return TARGET_ENOTTY;
-#ifdef ETXTBSY
-    case ETXTBSY:   return TARGET_ETXTBSY;
-#endif
-    case EFBIG:     return TARGET_EFBIG;
-    case ENOSPC:    return TARGET_ENOSPC;
-    case ESPIPE:    return TARGET_ESPIPE;
-    case EROFS:     return TARGET_EROFS;
-    case EMLINK:    return TARGET_EMLINK;
-    case EPIPE:     return TARGET_EPIPE;
-    case EDOM:      return TARGET_EDOM;
-    case ERANGE:    return TARGET_ERANGE;
-    case ENOSYS:    return TARGET_ENOSYS;
-#ifdef ELOOP
-    case ELOOP:     return TARGET_ELOOP;
-#endif
-    };
+    CPUXtensaState *env = cs->env_ptr;
 
-    return TARGET_EINVAL;
-}
+#define E(N) case E##N: err = TARGET_E##N; break
 
-typedef struct XtensaSimConsole {
-    CharBackend be;
-    struct {
-        char buffer[16];
-        size_t offset;
-    } input;
-} XtensaSimConsole;
-
-static XtensaSimConsole *sim_console;
-
-static IOCanReadHandler sim_console_can_read;
-static int sim_console_can_read(void *opaque)
-{
-    XtensaSimConsole *p = opaque;
-
-    return sizeof(p->input.buffer) - p->input.offset;
-}
-
-static IOReadHandler sim_console_read;
-static void sim_console_read(void *opaque, const uint8_t *buf, int size)
-{
-    XtensaSimConsole *p = opaque;
-    size_t copy = sizeof(p->input.buffer) - p->input.offset;
-
-    if (size < copy) {
-        copy = size;
+    switch (err) {
+    E(PERM);
+    E(NOENT);
+    E(INTR);
+    E(BADF);
+    E(ACCES);
+    E(FAULT);
+    E(BUSY);
+    E(EXIST);
+    E(NODEV);
+    E(NOTDIR);
+    E(ISDIR);
+    E(INVAL);
+    E(NFILE);
+    E(MFILE);
+    E(FBIG);
+    E(NOSPC);
+    E(SPIPE);
+    E(ROFS);
+    case GDB_ENAMETOOLONG:
+        err = TARGET_EINVAL;
+        break;
     }
-    memcpy(p->input.buffer + p->input.offset, buf, copy);
-    p->input.offset += copy;
+
+    env->regs[3] = err;
+    env->regs[2] = ret;
+
+#undef E
 }
 
-void xtensa_sim_open_console(Chardev *chr)
+static void xtensa_select_cb(CPUState *cs, uint64_t ret, int err)
 {
-    static XtensaSimConsole console;
-
-    qemu_chr_fe_init(&console.be, chr, &error_abort);
-    qemu_chr_fe_set_handlers(&console.be,
-                             sim_console_can_read,
-                             sim_console_read,
-                             NULL, NULL, &console,
-                             NULL, true);
-    sim_console = &console;
+    if (ret & G_IO_NVAL) {
+        xtensa_cb(cs, -1, GDB_EBADF);
+    } else {
+        xtensa_cb(cs, ret != 0, 0);
+    }
 }
 
 void xtensa_semihosting(CPUXtensaState *env)
@@ -194,165 +146,64 @@ void xtensa_semihosting(CPUXtensaState *env)
 
     switch (regs[2]) {
     case TARGET_SYS_exit:
+        gdb_exit(regs[3]);
         exit(regs[3]);
         break;
 
     case TARGET_SYS_read:
+        semihost_sys_read(cs, xtensa_cb, regs[3], regs[4], regs[5]);
+        break;
     case TARGET_SYS_write:
-        {
-            bool is_write = regs[2] == TARGET_SYS_write;
-            uint32_t fd = regs[3];
-            uint32_t vaddr = regs[4];
-            uint32_t len = regs[5];
-            uint32_t len_done = 0;
-
-            while (len > 0) {
-                hwaddr paddr = cpu_get_phys_page_debug(cs, vaddr);
-                uint32_t page_left =
-                    TARGET_PAGE_SIZE - (vaddr & (TARGET_PAGE_SIZE - 1));
-                uint32_t io_sz = page_left < len ? page_left : len;
-                hwaddr sz = io_sz;
-                void *buf = cpu_physical_memory_map(paddr, &sz, !is_write);
-                uint32_t io_done;
-                bool error = false;
-
-                if (buf) {
-                    vaddr += io_sz;
-                    len -= io_sz;
-                    if (fd < 3 && sim_console) {
-                        if (is_write && (fd == 1 || fd == 2)) {
-                            io_done = qemu_chr_fe_write_all(&sim_console->be,
-                                                            buf, io_sz);
-                            regs[3] = errno_h2g(errno);
-                        } else if (!is_write && fd == 0) {
-                            if (sim_console->input.offset) {
-                                io_done = sim_console->input.offset;
-                                if (io_sz < io_done) {
-                                    io_done = io_sz;
-                                }
-                                memcpy(buf, sim_console->input.buffer, io_done);
-                                memmove(sim_console->input.buffer,
-                                        sim_console->input.buffer + io_done,
-                                        sim_console->input.offset - io_done);
-                                sim_console->input.offset -= io_done;
-                                qemu_chr_fe_accept_input(&sim_console->be);
-                            } 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",
-                                          is_write ?
-                                          "writing to" : "reading from", fd);
-                            io_done = -1;
-                            regs[3] = TARGET_EBADF;
-                        }
-                    } else {
-                        io_done = is_write ?
-                            write(fd, buf, io_sz) :
-                            read(fd, buf, io_sz);
-                        regs[3] = errno_h2g(errno);
-                    }
-                    if (io_done == -1) {
-                        error = true;
-                        io_done = 0;
-                    }
-                    cpu_physical_memory_unmap(buf, sz, !is_write, io_done);
-                } else {
-                    error = true;
-                    regs[3] = TARGET_EINVAL;
-                    break;
-                }
-                if (error) {
-                    if (!len_done) {
-                        len_done = -1;
-                    }
-                    break;
-                }
-                len_done += io_done;
-                if (io_done < io_sz) {
-                    break;
-                }
-            }
-            regs[2] = len_done;
-        }
+        semihost_sys_write(cs, xtensa_cb, regs[3], regs[4], regs[5]);
         break;
-
     case TARGET_SYS_open:
-        {
-            char name[1024];
-            int rc;
-            int i;
-
-            for (i = 0; i < ARRAY_SIZE(name); ++i) {
-                rc = cpu_memory_rw_debug(cs, regs[3] + i,
-                                         (uint8_t *)name + i, 1, 0);
-                if (rc != 0 || name[i] == 0) {
-                    break;
-                }
-            }
-
-            if (rc == 0 && i < ARRAY_SIZE(name)) {
-                regs[2] = open(name, regs[4], regs[5]);
-                regs[3] = errno_h2g(errno);
-            } else {
-                regs[2] = -1;
-                regs[3] = TARGET_EINVAL;
-            }
-        }
+        semihost_sys_open(cs, xtensa_cb, regs[3], 0, regs[4], regs[5]);
         break;
-
     case TARGET_SYS_close:
-        if (regs[3] < 3) {
-            regs[2] = regs[3] = 0;
-        } else {
-            regs[2] = close(regs[3]);
-            regs[3] = errno_h2g(errno);
-        }
+        semihost_sys_close(cs, xtensa_cb, regs[3]);
         break;
-
     case TARGET_SYS_lseek:
-        regs[2] = lseek(regs[3], (off_t)(int32_t)regs[4], regs[5]);
-        regs[3] = errno_h2g(errno);
+        semihost_sys_lseek(cs, xtensa_cb, regs[3], regs[4], regs[5]);
         break;
 
     case TARGET_SYS_select_one:
         {
-            uint32_t fd = regs[3];
-            uint32_t rq = regs[4];
-            uint32_t target_tv = regs[5];
-            uint32_t target_tvv[2];
+            int timeout, events;
 
-            struct timeval tv = {0};
+            if (regs[5]) {
+                uint32_t tv_sec, tv_usec;
+                uint64_t msec;
 
-            if (target_tv) {
-                cpu_memory_rw_debug(cs, target_tv,
-                        (uint8_t *)target_tvv, sizeof(target_tvv), 0);
-                tv.tv_sec = (int32_t)tswap32(target_tvv[0]);
-                tv.tv_usec = (int32_t)tswap32(target_tvv[1]);
-            }
-            if (fd < 3 && 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_console->input.offset > 0;
-                } else {
-                    regs[2] = 0;
+                if (get_user_u32(tv_sec, regs[5]) ||
+                    get_user_u32(tv_usec, regs[5])) {
+                    xtensa_cb(cs, -1, GDB_EFAULT);
+                    return;
                 }
-                regs[3] = 0;
-            } else {
-                fd_set fdset;
 
-                FD_ZERO(&fdset);
-                FD_SET(fd, &fdset);
-                regs[2] = select(fd + 1,
-                                 rq == SELECT_ONE_READ   ? &fdset : NULL,
-                                 rq == SELECT_ONE_WRITE  ? &fdset : NULL,
-                                 rq == SELECT_ONE_EXCEPT ? &fdset : NULL,
-                                 target_tv ? &tv : NULL);
-                regs[3] = errno_h2g(errno);
+                /* Poll timeout is in milliseconds; overflow to infinity. */
+                msec = tv_sec * 1000ull + DIV_ROUND_UP(tv_usec, 1000ull);
+                timeout = msec <= INT32_MAX ? msec : -1;
+            } else {
+                timeout = -1;
             }
+
+            switch (regs[4]) {
+            case SELECT_ONE_READ:
+                events = G_IO_IN;
+                break;
+            case SELECT_ONE_WRITE:
+                events = G_IO_OUT;
+                break;
+            case SELECT_ONE_EXCEPT:
+                events = G_IO_PRI;
+                break;
+            default:
+                xtensa_cb(cs, -1, GDB_EINVAL);
+                return;
+            }
+
+            semihost_sys_poll_one(cs, xtensa_select_cb,
+                                  regs[3], events, timeout);
         }
         break;
 
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 67/74] tests/docker: Add debian-rx-cross image
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (65 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 66/74] target/xtensa: Use semihosting/syscalls.h Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 68/74] hw/rx: Handle a kernel file that is ELF Richard Henderson
                   ` (6 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

Build the entire cross tool chain from source.
For this reason, default to caching.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 MAINTAINERS                                   |  1 +
 tests/docker/Makefile.include                 |  6 ++
 .../debian-rx-cross.d/build-toolchain.sh      | 58 +++++++++++++++++++
 tests/tcg/configure.sh                        |  6 ++
 4 files changed, 71 insertions(+)
 create mode 100755 tests/docker/dockerfiles/debian-rx-cross.d/build-toolchain.sh

diff --git a/MAINTAINERS b/MAINTAINERS
index 294c88ace9..62d2640f35 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -297,6 +297,7 @@ RENESAS RX CPUs
 R: Yoshinori Sato <ysato@users.sourceforge.jp>
 S: Orphan
 F: target/rx/
+F: tests/docker/dockerfiles/debian-rx-cross.d/build-toolchain.sh
 
 S390 TCG CPUs
 M: Richard Henderson <richard.henderson@linaro.org>
diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include
index ca2157db46..1795a49da2 100644
--- a/tests/docker/Makefile.include
+++ b/tests/docker/Makefile.include
@@ -142,6 +142,10 @@ docker-image-debian-nios2-cross: $(DOCKER_FILES_DIR)/debian-toolchain.docker \
     $(DOCKER_FILES_DIR)/debian-nios2-cross.d/build-toolchain.sh
 	$(call debian-toolchain, $@)
 
+docker-image-debian-rx-cross: $(DOCKER_FILES_DIR)/debian-toolchain.docker \
+    $(DOCKER_FILES_DIR)/debian-rx-cross.d/build-toolchain.sh
+	$(call debian-toolchain, $@)
+
 # Specialist build images, sometimes very limited tools
 docker-image-debian-tricore-cross: docker-image-debian10
 docker-image-debian-all-test-cross: docker-image-debian10
@@ -149,6 +153,7 @@ docker-image-debian-microblaze-cross: docker-image-debian10
 docker-image-debian-nios2-cross: docker-image-debian10
 docker-image-debian-powerpc-test-cross: docker-image-debian11
 docker-image-debian-riscv64-test-cross: docker-image-debian11
+docker-image-debian-rx-cross: docker-image-debian10
 
 # These images may be good enough for building tests but not for test builds
 DOCKER_PARTIAL_IMAGES += debian-alpha-cross
@@ -158,6 +163,7 @@ DOCKER_PARTIAL_IMAGES += debian-m68k-cross debian-mips64-cross
 DOCKER_PARTIAL_IMAGES += debian-microblaze-cross
 DOCKER_PARTIAL_IMAGES += debian-nios2-cross
 DOCKER_PARTIAL_IMAGES += debian-riscv64-test-cross
+DOCKER_PARTIAL_IMAGES += debian-rx-cross
 DOCKER_PARTIAL_IMAGES += debian-sh4-cross debian-sparc64-cross
 DOCKER_PARTIAL_IMAGES += debian-tricore-cross
 DOCKER_PARTIAL_IMAGES += debian-xtensa-cross
diff --git a/tests/docker/dockerfiles/debian-rx-cross.d/build-toolchain.sh b/tests/docker/dockerfiles/debian-rx-cross.d/build-toolchain.sh
new file mode 100755
index 0000000000..0d22280dee
--- /dev/null
+++ b/tests/docker/dockerfiles/debian-rx-cross.d/build-toolchain.sh
@@ -0,0 +1,58 @@
+#!/bin/bash
+
+set -e
+
+TARGET=rx-elf
+
+J=$(expr $(nproc) / 2)
+TOOLCHAIN_INSTALL=/usr/local
+TOOLCHAIN_BIN=${TOOLCHAIN_INSTALL}/bin
+CROSS_SYSROOT=${TOOLCHAIN_INSTALL}/$TARGET/sys-root
+
+export PATH=${TOOLCHAIN_BIN}:$PATH
+
+#
+# Grab all of the source for the toolchain bootstrap.
+#
+
+wget https://ftp.gnu.org/gnu/binutils/binutils-2.37.tar.xz
+wget https://ftp.gnu.org/gnu/gcc/gcc-11.2.0/gcc-11.2.0.tar.xz
+
+tar axf binutils-2.37.tar.xz
+tar axf gcc-11.2.0.tar.xz
+
+git clone --depth 1 --branch newlib-4.1.0 \
+  https://sourceware.org/git/newlib-cygwin.git newlib-4.1.0
+
+# Create a combined gcc/newlib source tree
+
+mkdir -p src/include
+cd src
+ln -s ../gcc*/* . || true
+ln -s ../newlib*/* . || true
+cd include
+ln -s ../../gcc*/include/* . || true
+ln -s ../../newlib*/include/* . || true
+cd ../../
+
+# Build binutils
+
+mkdir -p bld-b
+cd bld-b
+../binu*/configure --disable-werror \
+  --prefix=${TOOLCHAIN_INSTALL} --with-sysroot --target=${TARGET}
+make -j${J}
+make install
+cd ..
+
+# Build gcc+newlib
+
+mkdir -p bld
+cd bld
+../src/configure --disable-werror --disable-shared \
+  --prefix=${TOOLCHAIN_INSTALL} --with-sysroot --target=${TARGET} \
+  --enable-languages=c --disable-libssp --disable-libsanitizer \
+  --disable-libatomic --disable-libgomp --disable-libquadmath
+make -j${J}
+make install
+cd ..
diff --git a/tests/tcg/configure.sh b/tests/tcg/configure.sh
index 691d90abac..34c94f3045 100755
--- a/tests/tcg/configure.sh
+++ b/tests/tcg/configure.sh
@@ -68,6 +68,7 @@ fi
 : ${cross_cc_ppc64le="$cross_cc_ppc64"}
 : ${cross_cc_cflags_ppc64le="-m64 -mlittle-endian"}
 : ${cross_cc_riscv64="riscv64-linux-gnu-gcc"}
+: ${cross_cc_rx="rx-elf-gcc"}
 : ${cross_cc_s390x="s390x-linux-gnu-gcc"}
 : ${cross_cc_sh4="sh4-linux-gnu-gcc"}
 : ${cross_cc_cflags_sparc="-m32 -mv8plus -mcpu=ultrasparc"}
@@ -192,6 +193,11 @@ for target in $target_list; do
       container_image=debian-riscv64-test-cross
       container_cross_cc=riscv64-linux-gnu-gcc
       ;;
+    rx-*)
+      container_hosts=x86_64
+      container_image=debian-rx-cross
+      container_cross_cc=rx-elf-gcc
+      ;;
     s390x-*)
       container_hosts=x86_64
       container_image=debian-s390x-cross
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 68/74] hw/rx: Handle a kernel file that is ELF
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (66 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 67/74] tests/docker: Add debian-rx-cross image Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-13 15:44   ` Peter Maydell
  2022-05-03 19:48 ` [PATCH v2 69/74] target/rx: Fix the base of the fixed vector table Richard Henderson
                   ` (5 subsequent siblings)
  73 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

Attempt to load the kernel with load_elf.  If this fails with
ELF_LOAD_NOT_ELF, continue to treat the kernel as a raw image.

This will be handy for running semihosting programs.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 hw/rx/rx-gdbsim.c | 24 +++++++++++++++++++++---
 1 file changed, 21 insertions(+), 3 deletions(-)

diff --git a/hw/rx/rx-gdbsim.c b/hw/rx/rx-gdbsim.c
index be147b4bd9..64b533181d 100644
--- a/hw/rx/rx-gdbsim.c
+++ b/hw/rx/rx-gdbsim.c
@@ -26,6 +26,7 @@
 #include "sysemu/device_tree.h"
 #include "hw/boards.h"
 #include "qom/object.h"
+#include "elf.h"
 
 /* Same address of GDB integrated simulator */
 #define SDRAM_BASE  EXT_CS_BASE
@@ -57,15 +58,32 @@ static void rx_load_image(RXCPU *cpu, const char *filename,
                           uint32_t start, uint32_t size)
 {
     static uint32_t extable[32];
-    long kernel_size;
+    ssize_t kernel_size;
+    uint64_t kernel_entry;
     int i;
 
+    /* Try an ELF image first. */
+
+    kernel_size = load_elf(filename, NULL, NULL, NULL, &kernel_entry,
+                           NULL, NULL, NULL, false, EM_RX, false, false);
+    if (kernel_size >= 0) {
+        cpu_set_pc(CPU(cpu), kernel_entry);
+        return;
+    }
+    if (kernel_size != ELF_LOAD_NOT_ELF) {
+        error_report("could not load kernel '%s': %s",
+                     filename, load_elf_strerror(kernel_size));
+        exit(1);
+    }
+
+    /* Not ELF: load a raw image, e.g. zImage. */
+
     kernel_size = load_image_targphys(filename, start, size);
     if (kernel_size < 0) {
-        fprintf(stderr, "qemu: could not load kernel '%s'\n", filename);
+        error_report("could not load kernel '%s'", filename);
         exit(1);
     }
-    cpu->env.pc = start;
+    cpu_set_pc(CPU(cpu), start);
 
     /* setup exception trap trampoline */
     /* linux kernel only works little-endian mode */
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 69/74] target/rx: Fix the base of the fixed vector table
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (67 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 68/74] hw/rx: Handle a kernel file that is ELF Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 70/74] target/rx: Name the exceptions Richard Henderson
                   ` (4 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

This begins at 0xffffff80 not 0xffffffc0.
This has caused exceptions to wrap around
to low memory instead of being at the top.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/rx/helper.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/rx/helper.c b/target/rx/helper.c
index f34945e7e2..c6e285657e 100644
--- a/target/rx/helper.c
+++ b/target/rx/helper.c
@@ -91,7 +91,7 @@ void rx_cpu_do_interrupt(CPUState *cs)
         cpu_stl_data(env, env->isp, env->pc);
 
         if (vec < 0x100) {
-            env->pc = cpu_ldl_data(env, 0xffffffc0 + vec * 4);
+            env->pc = cpu_ldl_data(env, 0xffffff80 + vec * 4);
         } else {
             env->pc = cpu_ldl_data(env, env->intb + (vec & 0xff) * 4);
         }
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 70/74] target/rx: Name the exceptions
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (68 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 69/74] target/rx: Fix the base of the fixed vector table Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 71/74] target/rx: Consolidate exception helpers Richard Henderson
                   ` (3 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

Provide EXCP_* names to the fixed and relocatable
vector table entries.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/rx/cpu.h       | 20 ++++++++++++++++++++
 target/rx/helper.c    | 25 ++++++++++++++++---------
 target/rx/op_helper.c | 15 +++++++--------
 3 files changed, 43 insertions(+), 17 deletions(-)

diff --git a/target/rx/cpu.h b/target/rx/cpu.h
index 5655dffeff..99e28fb70f 100644
--- a/target/rx/cpu.h
+++ b/target/rx/cpu.h
@@ -66,6 +66,26 @@ enum {
     NUM_REGS = 16,
 };
 
+enum {
+    /*
+     * The Fixed Vector Table begins at 0xffffff80 and contains 32 entries,
+     * most of which are reserved.
+     */
+    EXCP_PRIVILEGED  = 20,
+    EXCP_ACCESS      = 21,
+    EXCP_UNDEFINED   = 23,
+    EXCP_FPU         = 25,
+    EXCP_NMI         = 30,
+    EXCP_RESET       = 31,
+
+    /*
+     * The Relocatable Vector Table begins at env->intb and
+     * contains 256 entries.
+     */
+    EXCP_INTB_0      = 0x100,
+    EXCP_INTB_255    = EXCP_INTB_0 + 255,
+};
+
 typedef struct CPUArchState {
     /* CPU registers */
     uint32_t regs[NUM_REGS];    /* general registers */
diff --git a/target/rx/helper.c b/target/rx/helper.c
index c6e285657e..29a4b075fa 100644
--- a/target/rx/helper.c
+++ b/target/rx/helper.c
@@ -83,36 +83,43 @@ void rx_cpu_do_interrupt(CPUState *cs)
         }
     } else {
         uint32_t vec = cs->exception_index;
-        const char *expname = "unknown exception";
+        const char *expname;
 
         env->isp -= 4;
         cpu_stl_data(env, env->isp, save_psw);
         env->isp -= 4;
         cpu_stl_data(env, env->isp, env->pc);
 
-        if (vec < 0x100) {
+        if (vec < EXCP_INTB_0) {
             env->pc = cpu_ldl_data(env, 0xffffff80 + vec * 4);
         } else {
-            env->pc = cpu_ldl_data(env, env->intb + (vec & 0xff) * 4);
+            env->pc = cpu_ldl_data(env, env->intb + (vec - EXCP_INTB_0) * 4);
         }
         switch (vec) {
-        case 20:
+        case EXCP_PRIVILEGED:
             expname = "privilege violation";
             break;
-        case 21:
+        case EXCP_ACCESS:
             expname = "access exception";
             break;
-        case 23:
+        case EXCP_UNDEFINED:
             expname = "illegal instruction";
             break;
-        case 25:
+        case EXCP_FPU:
             expname = "fpu exception";
             break;
-        case 30:
+        case EXCP_NMI:
             expname = "non-maskable interrupt";
             break;
-        case 0x100 ... 0x1ff:
+        case EXCP_RESET:
+            expname = "reset interrupt";
+            break;
+        case EXCP_INTB_0 ... EXCP_INTB_255:
             expname = "unconditional trap";
+            break;
+        default:
+            expname = "unknown exception";
+            break;
         }
         qemu_log_mask(CPU_LOG_INT, "exception 0x%02x [%s] raised\n",
                       (vec & 0xff), expname);
diff --git a/target/rx/op_helper.c b/target/rx/op_helper.c
index 9ca32dcc82..6ab7b070bd 100644
--- a/target/rx/op_helper.c
+++ b/target/rx/op_helper.c
@@ -114,7 +114,7 @@ static void update_fpsw(CPURXState *env, float32 ret, uintptr_t retaddr)
         enable = FIELD_EX32(env->fpsw, FPSW, ENABLE);
         enable |= 1 << 5; /* CE always enabled */
         if (cause & enable) {
-            raise_exception(env, 21, retaddr);
+            raise_exception(env, EXCP_FPU, retaddr);
         }
     }
 }
@@ -420,8 +420,7 @@ uint32_t helper_divu(CPURXState *env, uint32_t num, uint32_t den)
 
 /* exception */
 static inline G_NORETURN
-void raise_exception(CPURXState *env, int index,
-                     uintptr_t retaddr)
+void raise_exception(CPURXState *env, int index, uintptr_t retaddr)
 {
     CPUState *cs = env_cpu(env);
 
@@ -431,17 +430,17 @@ void raise_exception(CPURXState *env, int index,
 
 G_NORETURN void helper_raise_privilege_violation(CPURXState *env)
 {
-    raise_exception(env, 20, GETPC());
+    raise_exception(env, EXCP_PRIVILEGED, GETPC());
 }
 
 G_NORETURN void helper_raise_access_fault(CPURXState *env)
 {
-    raise_exception(env, 21, GETPC());
+    raise_exception(env, EXCP_ACCESS, GETPC());
 }
 
 G_NORETURN void helper_raise_illegal_instruction(CPURXState *env)
 {
-    raise_exception(env, 23, GETPC());
+    raise_exception(env, EXCP_UNDEFINED, GETPC());
 }
 
 G_NORETURN void helper_wait(CPURXState *env)
@@ -456,10 +455,10 @@ G_NORETURN void helper_wait(CPURXState *env)
 
 G_NORETURN void helper_rxint(CPURXState *env, uint32_t vec)
 {
-    raise_exception(env, 0x100 + vec, 0);
+    raise_exception(env, EXCP_INTB_0 + vec, 0);
 }
 
 G_NORETURN void helper_rxbrk(CPURXState *env)
 {
-    raise_exception(env, 0x100, 0);
+    raise_exception(env, EXCP_INTB_0, 0);
 }
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 71/74] target/rx: Consolidate exception helpers
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (69 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 70/74] target/rx: Name the exceptions Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 72/74] target/rx: Cleanup rx_cpu_do_interrupt Richard Henderson
                   ` (2 subsequent siblings)
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

Replace 5 helpers with 1.  Store pc before raising
privileged and undefined instruction exceptions,
which means we don't need to use tcg unwinding.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/rx/helper.h    |  6 +-----
 target/rx/op_helper.c | 25 ++++---------------------
 target/rx/translate.c | 23 +++++++++++------------
 3 files changed, 16 insertions(+), 38 deletions(-)

diff --git a/target/rx/helper.h b/target/rx/helper.h
index ebb4739474..e6763b5a90 100644
--- a/target/rx/helper.h
+++ b/target/rx/helper.h
@@ -1,9 +1,5 @@
-DEF_HELPER_1(raise_illegal_instruction, noreturn, env)
-DEF_HELPER_1(raise_access_fault, noreturn, env)
-DEF_HELPER_1(raise_privilege_violation, noreturn, env)
+DEF_HELPER_2(raise_exception, noreturn, env, i32)
 DEF_HELPER_1(wait, noreturn, env)
-DEF_HELPER_2(rxint, noreturn, env, i32)
-DEF_HELPER_1(rxbrk, noreturn, env)
 DEF_HELPER_FLAGS_3(fadd, TCG_CALL_NO_WG, f32, env, f32, f32)
 DEF_HELPER_FLAGS_3(fsub, TCG_CALL_NO_WG, f32, env, f32, f32)
 DEF_HELPER_FLAGS_3(fmul, TCG_CALL_NO_WG, f32, env, f32, f32)
diff --git a/target/rx/op_helper.c b/target/rx/op_helper.c
index 6ab7b070bd..f2b58bcad5 100644
--- a/target/rx/op_helper.c
+++ b/target/rx/op_helper.c
@@ -428,19 +428,12 @@ void raise_exception(CPURXState *env, int index, uintptr_t retaddr)
     cpu_loop_exit_restore(cs, retaddr);
 }
 
-G_NORETURN void helper_raise_privilege_violation(CPURXState *env)
+G_NORETURN void helper_raise_exception(CPURXState *env, uint32_t index)
 {
-    raise_exception(env, EXCP_PRIVILEGED, GETPC());
-}
+    CPUState *cs = env_cpu(env);
 
-G_NORETURN void helper_raise_access_fault(CPURXState *env)
-{
-    raise_exception(env, EXCP_ACCESS, GETPC());
-}
-
-G_NORETURN void helper_raise_illegal_instruction(CPURXState *env)
-{
-    raise_exception(env, EXCP_UNDEFINED, GETPC());
+    cs->exception_index = index;
+    cpu_loop_exit(cs);
 }
 
 G_NORETURN void helper_wait(CPURXState *env)
@@ -452,13 +445,3 @@ G_NORETURN void helper_wait(CPURXState *env)
     env->psw_i = 1;
     raise_exception(env, EXCP_HLT, 0);
 }
-
-G_NORETURN void helper_rxint(CPURXState *env, uint32_t vec)
-{
-    raise_exception(env, EXCP_INTB_0 + vec, 0);
-}
-
-G_NORETURN void helper_rxbrk(CPURXState *env)
-{
-    raise_exception(env, EXCP_INTB_0, 0);
-}
diff --git a/target/rx/translate.c b/target/rx/translate.c
index 62aee66937..ddf31afb11 100644
--- a/target/rx/translate.c
+++ b/target/rx/translate.c
@@ -156,6 +156,13 @@ static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
     dc->base.is_jmp = DISAS_NORETURN;
 }
 
+static void gen_raise_exception(DisasContext *ctx, int vec, bool advance_pc)
+{
+    tcg_gen_movi_i32(cpu_pc, advance_pc ? ctx->base.pc_next : ctx->pc);
+    gen_helper_raise_exception(cpu_env, tcg_constant_i32(vec));
+    ctx->base.is_jmp = DISAS_NORETURN;
+}
+
 /* generic load wrapper */
 static inline void rx_gen_ld(unsigned int size, TCGv reg, TCGv mem)
 {
@@ -234,7 +241,7 @@ static int is_privileged(DisasContext *ctx, int is_exception)
 {
     if (FIELD_EX32(ctx->tb_flags, PSW, PM)) {
         if (is_exception) {
-            gen_helper_raise_privilege_violation(cpu_env);
+            gen_raise_exception(ctx, EXCP_PRIVILEGED, false);
         }
         return 0;
     } else {
@@ -2261,23 +2268,15 @@ static bool trans_RTE(DisasContext *ctx, arg_RTE *a)
 /* brk */
 static bool trans_BRK(DisasContext *ctx, arg_BRK *a)
 {
-    tcg_gen_movi_i32(cpu_pc, ctx->base.pc_next);
-    gen_helper_rxbrk(cpu_env);
-    ctx->base.is_jmp = DISAS_NORETURN;
+    gen_raise_exception(ctx, EXCP_INTB_0, true);
     return true;
 }
 
 /* int #imm */
 static bool trans_INT(DisasContext *ctx, arg_INT *a)
 {
-    TCGv vec;
-
     tcg_debug_assert(a->imm < 0x100);
-    vec = tcg_const_i32(a->imm);
-    tcg_gen_movi_i32(cpu_pc, ctx->base.pc_next);
-    gen_helper_rxint(cpu_env, vec);
-    tcg_temp_free(vec);
-    ctx->base.is_jmp = DISAS_NORETURN;
+    gen_raise_exception(ctx, EXCP_INTB_0 + a->imm, true);
     return true;
 }
 
@@ -2318,7 +2317,7 @@ static void rx_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
     ctx->pc = ctx->base.pc_next;
     insn = decode_load(ctx);
     if (!decode(ctx, insn)) {
-        gen_helper_raise_illegal_instruction(cpu_env);
+        gen_raise_exception(ctx, EXCP_UNDEFINED, false);
     }
 }
 
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 72/74] target/rx: Cleanup rx_cpu_do_interrupt
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (70 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 71/74] target/rx: Consolidate exception helpers Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 73/74] target/rx: Implement libgloss semihosting Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 74/74] tests/tcg/rx: Enable semihosting multiarch tests Richard Henderson
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

Introduce EXCP_IRQ and EXCP_FIRQ to remember the decision
that we made in rx_cpu_exec_interrupt.  Use a switch to
select between exceptions; unify stacked interrupt frame
creation; abort if unknown exception.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/rx/cpu.h    |   4 ++
 target/rx/helper.c | 118 ++++++++++++++++++++++-----------------------
 2 files changed, 61 insertions(+), 61 deletions(-)

diff --git a/target/rx/cpu.h b/target/rx/cpu.h
index 99e28fb70f..5b93c0dcb0 100644
--- a/target/rx/cpu.h
+++ b/target/rx/cpu.h
@@ -84,6 +84,10 @@ enum {
      */
     EXCP_INTB_0      = 0x100,
     EXCP_INTB_255    = EXCP_INTB_0 + 255,
+
+    /* Private to the qemu implementation. */
+    EXCP_IRQ,
+    EXCP_FIRQ,
 };
 
 typedef struct CPUArchState {
diff --git a/target/rx/helper.c b/target/rx/helper.c
index 29a4b075fa..d12e551cc2 100644
--- a/target/rx/helper.c
+++ b/target/rx/helper.c
@@ -42,12 +42,13 @@ void rx_cpu_unpack_psw(CPURXState *env, uint32_t psw, int rte)
 
 #ifndef CONFIG_USER_ONLY
 
-#define INT_FLAGS (CPU_INTERRUPT_HARD | CPU_INTERRUPT_FIR)
 void rx_cpu_do_interrupt(CPUState *cs)
 {
     RXCPU *cpu = RX_CPU(cs);
     CPURXState *env = &cpu->env;
-    int do_irq = cs->interrupt_request & INT_FLAGS;
+    uint32_t vec = cs->exception_index;
+    target_ulong vec_table = 0xffffff80u; /* fixed vector table */
+    const char *expname;
     uint32_t save_psw;
 
     env->in_sleep = 0;
@@ -60,69 +61,62 @@ void rx_cpu_do_interrupt(CPUState *cs)
     save_psw = rx_cpu_pack_psw(env);
     env->psw_pm = env->psw_i = env->psw_u = 0;
 
-    if (do_irq) {
-        if (do_irq & CPU_INTERRUPT_FIR) {
-            env->bpc = env->pc;
-            env->bpsw = save_psw;
-            env->pc = env->fintv;
-            env->psw_ipl = 15;
-            cs->interrupt_request &= ~CPU_INTERRUPT_FIR;
-            qemu_set_irq(env->ack, env->ack_irq);
-            qemu_log_mask(CPU_LOG_INT, "fast interrupt raised\n");
-        } else if (do_irq & CPU_INTERRUPT_HARD) {
-            env->isp -= 4;
-            cpu_stl_data(env, env->isp, save_psw);
-            env->isp -= 4;
-            cpu_stl_data(env, env->isp, env->pc);
-            env->pc = cpu_ldl_data(env, env->intb + env->ack_irq * 4);
-            env->psw_ipl = env->ack_ipl;
-            cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
-            qemu_set_irq(env->ack, env->ack_irq);
-            qemu_log_mask(CPU_LOG_INT,
-                          "interrupt 0x%02x raised\n", env->ack_irq);
-        }
-    } else {
-        uint32_t vec = cs->exception_index;
-        const char *expname;
+    switch (vec) {
+    case EXCP_FIRQ:
+        env->bpc = env->pc;
+        env->bpsw = save_psw;
+        env->pc = env->fintv;
+        env->psw_ipl = 15;
+        cs->interrupt_request &= ~CPU_INTERRUPT_FIR;
+        qemu_set_irq(env->ack, env->ack_irq);
+        qemu_log_mask(CPU_LOG_INT, "fast interrupt raised\n");
+        break;
 
+    case EXCP_IRQ:
+        env->psw_ipl = env->ack_ipl;
+        cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
+        qemu_set_irq(env->ack, env->ack_irq);
+        expname = "interrupt";
+        vec_table = env->intb;
+        vec = env->ack_ipl;
+        goto do_stacked;
+
+    case EXCP_PRIVILEGED:
+        expname = "privilege violation";
+        goto do_stacked;
+    case EXCP_ACCESS:
+        expname = "access exception";
+        goto do_stacked;
+    case EXCP_UNDEFINED:
+        expname = "illegal instruction";
+        goto do_stacked;
+    case EXCP_FPU:
+        expname = "fpu exception";
+        goto do_stacked;
+    case EXCP_NMI:
+        expname = "non-maskable interrupt";
+        goto do_stacked;
+    case EXCP_RESET:
+        expname = "reset interrupt";
+        goto do_stacked;
+
+    case EXCP_INTB_0 ... EXCP_INTB_255:
+        expname = "unconditional trap";
+        vec_table = env->intb;
+        vec -= EXCP_INTB_0;
+        goto do_stacked;
+
+    do_stacked:
         env->isp -= 4;
         cpu_stl_data(env, env->isp, save_psw);
         env->isp -= 4;
         cpu_stl_data(env, env->isp, env->pc);
+        env->pc = cpu_ldl_data(env, vec_table + vec * 4);
+        qemu_log_mask(CPU_LOG_INT, "%s raised (0x%02x)\n", expname, vec);
+        break;
 
-        if (vec < EXCP_INTB_0) {
-            env->pc = cpu_ldl_data(env, 0xffffff80 + vec * 4);
-        } else {
-            env->pc = cpu_ldl_data(env, env->intb + (vec - EXCP_INTB_0) * 4);
-        }
-        switch (vec) {
-        case EXCP_PRIVILEGED:
-            expname = "privilege violation";
-            break;
-        case EXCP_ACCESS:
-            expname = "access exception";
-            break;
-        case EXCP_UNDEFINED:
-            expname = "illegal instruction";
-            break;
-        case EXCP_FPU:
-            expname = "fpu exception";
-            break;
-        case EXCP_NMI:
-            expname = "non-maskable interrupt";
-            break;
-        case EXCP_RESET:
-            expname = "reset interrupt";
-            break;
-        case EXCP_INTB_0 ... EXCP_INTB_255:
-            expname = "unconditional trap";
-            break;
-        default:
-            expname = "unknown exception";
-            break;
-        }
-        qemu_log_mask(CPU_LOG_INT, "exception 0x%02x [%s] raised\n",
-                      (vec & 0xff), expname);
+    default:
+        g_assert_not_reached();
     }
     env->regs[0] = env->isp;
 }
@@ -132,19 +126,21 @@ bool rx_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
     RXCPU *cpu = RX_CPU(cs);
     CPURXState *env = &cpu->env;
     int accept = 0;
+
     /* hardware interrupt (Normal) */
     if ((interrupt_request & CPU_INTERRUPT_HARD) &&
         env->psw_i && (env->psw_ipl < env->req_ipl)) {
         env->ack_irq = env->req_irq;
         env->ack_ipl = env->req_ipl;
-        accept = 1;
+        accept = EXCP_IRQ;
     }
     /* hardware interrupt (FIR) */
     if ((interrupt_request & CPU_INTERRUPT_FIR) &&
         env->psw_i && (env->psw_ipl < 15)) {
-        accept = 1;
+        accept = EXCP_FIRQ;
     }
     if (accept) {
+        cs->exception_index = accept;
         rx_cpu_do_interrupt(cs);
         return true;
     }
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 73/74] target/rx: Implement libgloss semihosting
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (71 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 72/74] target/rx: Cleanup rx_cpu_do_interrupt Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  2022-05-03 19:48 ` [PATCH v2 74/74] tests/tcg/rx: Enable semihosting multiarch tests Richard Henderson
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 configs/devices/rx-softmmu/default.mak |   1 +
 target/rx/cpu.h                        |   2 +
 target/rx/helper.c                     |   5 +
 target/rx/rx-semi.c                    | 165 +++++++++++++++++++++++++
 target/rx/translate.c                  |   7 +-
 qemu-options.hx                        |  13 +-
 target/rx/meson.build                  |   4 +-
 7 files changed, 189 insertions(+), 8 deletions(-)
 create mode 100644 target/rx/rx-semi.c

diff --git a/configs/devices/rx-softmmu/default.mak b/configs/devices/rx-softmmu/default.mak
index df2b4e4f42..5c1033a2d3 100644
--- a/configs/devices/rx-softmmu/default.mak
+++ b/configs/devices/rx-softmmu/default.mak
@@ -1,3 +1,4 @@
 # Default configuration for rx-softmmu
 
 CONFIG_RX_GDBSIM=y
+CONFIG_SEMIHOSTING=y
diff --git a/target/rx/cpu.h b/target/rx/cpu.h
index 5b93c0dcb0..117cfea027 100644
--- a/target/rx/cpu.h
+++ b/target/rx/cpu.h
@@ -88,6 +88,7 @@ enum {
     /* Private to the qemu implementation. */
     EXCP_IRQ,
     EXCP_FIRQ,
+    EXCP_SEMIHOST,
 };
 
 typedef struct CPUArchState {
@@ -147,6 +148,7 @@ const char *rx_crname(uint8_t cr);
 #ifndef CONFIG_USER_ONLY
 void rx_cpu_do_interrupt(CPUState *cpu);
 bool rx_cpu_exec_interrupt(CPUState *cpu, int int_req);
+void rx_cpu_do_semihosting(CPURXState *env);
 #endif /* !CONFIG_USER_ONLY */
 void rx_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
 int rx_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
diff --git a/target/rx/helper.c b/target/rx/helper.c
index d12e551cc2..00f72b2090 100644
--- a/target/rx/helper.c
+++ b/target/rx/helper.c
@@ -53,6 +53,11 @@ void rx_cpu_do_interrupt(CPUState *cs)
 
     env->in_sleep = 0;
 
+    if (vec == EXCP_SEMIHOST) {
+        rx_cpu_do_semihosting(env);
+        return;
+    }
+
     if (env->psw_u) {
         env->usp = env->regs[0];
     } else {
diff --git a/target/rx/rx-semi.c b/target/rx/rx-semi.c
new file mode 100644
index 0000000000..f2406ad219
--- /dev/null
+++ b/target/rx/rx-semi.c
@@ -0,0 +1,165 @@
+/*
+ *  gdbsim semihosting syscall interface.
+ *  The semihosting protocol implemented here is described in
+ *
+ *  libgloss sources:
+ *  https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;a=blob;f=libgloss/syscall.h;hb=HEAD
+ *
+ *  gdb sources:
+ *  https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=blob;f=sim/rx/syscalls.c;hb=HEAD
+ *
+ *  Copyright (c) 2022 Linaro, Ltd.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "exec/gdbstub.h"
+#include "semihosting/syscalls.h"
+#include "qemu/log.h"
+
+/*
+ * These are the syscall numbers from libgloss/syscall.h,
+ * but note that not all of them are implemented.
+ */
+enum {
+    TARGET_SYS_exit = 1,
+    TARGET_SYS_open,
+    TARGET_SYS_close,
+    TARGET_SYS_read,
+    TARGET_SYS_write,
+    TARGET_SYS_lseek,
+    TARGET_SYS_unlink,
+    TARGET_SYS_getpid,
+    TARGET_SYS_kill,
+    TARGET_SYS_fstat,
+    TARGET_SYS_sbrk,
+    TARGET_SYS_argvlen,
+    TARGET_SYS_argv,
+    TARGET_SYS_chdir,
+    TARGET_SYS_stat,
+    TARGET_SYS_chmod,
+    TARGET_SYS_utime,
+    TARGET_SYS_time,
+    TARGET_SYS_gettimeofday,
+    TARGET_SYS_times,
+    TARGET_SYS_link,
+    TARGET_SYS_argc,
+    TARGET_SYS_argnlen,
+    TARGET_SYS_argn,
+    TARGET_SYS_reconfig,
+};
+
+static void rx_semi_cb(CPUState *cs, uint64_t ret, int err)
+{
+    CPURXState *env = cs->env_ptr;
+
+    /* There is no concept of errno in this interface. */
+    env->regs[1] = ret;
+}
+
+static bool rx_semi_arg(CPURXState *env, uint32_t *ret, int argn)
+{
+    if (argn < 4) {
+        *ret = env->regs[argn + 1];
+    } else {
+        uint32_t stack_addr = env->regs[0] + 4 + (argn - 4) * 4;
+        if (cpu_memory_rw_debug(env_cpu(env), stack_addr, ret, 4, 0)) {
+            return false;
+        }
+        tswap32s(ret);
+    }
+    return true;
+}
+
+#define GET_ARG(E, N) \
+    ({ uint32_t v_; if (!rx_semi_arg((E), &v_, (N))) goto failed; v_; })
+
+void rx_cpu_do_semihosting(CPURXState *env)
+{
+    CPUState *cs = env_cpu(env);
+    uint32_t nr = env->regs[5];
+    uint32_t a0, a1, a2;
+
+    switch (nr) {
+    case TARGET_SYS_exit:
+        a0 = GET_ARG(env, 0);
+        gdb_exit(a0);
+        exit(a0);
+
+    case TARGET_SYS_open:
+        /*
+         * This function is declared int open(char *path, int flags, ...),
+         * which means that only the first argument is in registers.
+         */
+        a0 = GET_ARG(env, 0);
+        a1 = GET_ARG(env, 4);
+        a2 = GET_ARG(env, 5);
+        semihost_sys_open(cs, rx_semi_cb, a0, 0, a1, a2);
+        break;
+
+    case TARGET_SYS_close:
+        a0 = GET_ARG(env, 0);
+        semihost_sys_close(cs, rx_semi_cb, a0);
+        break;
+
+    case TARGET_SYS_read:
+        a0 = GET_ARG(env, 0);
+        a1 = GET_ARG(env, 1);
+        a2 = GET_ARG(env, 2);
+        semihost_sys_read(cs, rx_semi_cb, a0, a1, a2);
+        break;
+
+    case TARGET_SYS_write:
+        a0 = GET_ARG(env, 0);
+        a1 = GET_ARG(env, 1);
+        a2 = GET_ARG(env, 2);
+        semihost_sys_write(cs, rx_semi_cb, a0, a1, a2);
+        break;
+
+    case TARGET_SYS_getpid:
+        rx_semi_cb(cs, 42, 0);
+        break;
+
+    case TARGET_SYS_gettimeofday:
+        a0 = GET_ARG(env, 0);
+        semihost_sys_gettimeofday(cs, rx_semi_cb, a0, 0);
+        break;
+
+    case TARGET_SYS_kill:
+        a0 = GET_ARG(env, 0);
+        if (a0 != 42) {
+            goto failed;
+        }
+        /* Without defined signal numbers, pretend they're all SIGABRT. */
+        gdb_exit(-1);
+        abort();
+
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "rx-semihosting: unsupported "
+                      "semihosting syscall %u\n", nr);
+        /* fall through */
+
+    failed:
+        rx_semi_cb(cs, -1, 0);
+        break;
+    }
+
+    /*
+     * Skip the semihosting insn (int #255).
+     * Must be done after any cpu_loop_exit() within the syscalls.
+     */
+    env->pc += 3;
+}
diff --git a/target/rx/translate.c b/target/rx/translate.c
index ddf31afb11..4a072661ca 100644
--- a/target/rx/translate.c
+++ b/target/rx/translate.c
@@ -27,6 +27,7 @@
 #include "exec/helper-gen.h"
 #include "exec/translator.h"
 #include "exec/log.h"
+#include "semihosting/semihost.h"
 
 typedef struct DisasContext {
     DisasContextBase base;
@@ -2276,7 +2277,11 @@ static bool trans_BRK(DisasContext *ctx, arg_BRK *a)
 static bool trans_INT(DisasContext *ctx, arg_INT *a)
 {
     tcg_debug_assert(a->imm < 0x100);
-    gen_raise_exception(ctx, EXCP_INTB_0 + a->imm, true);
+    if (semihosting_enabled() && a->imm == 0xff) {
+        gen_raise_exception(ctx, EXCP_SEMIHOST, false);
+    } else {
+        gen_raise_exception(ctx, EXCP_INTB_0 + a->imm, true);
+    }
     return true;
 }
 
diff --git a/qemu-options.hx b/qemu-options.hx
index 5f69b94b8e..4feb969b14 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -4530,10 +4530,11 @@ ERST
 DEF("semihosting", 0, QEMU_OPTION_semihosting,
     "-semihosting    semihosting mode\n",
     QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA |
-    QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV)
+    QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV | QEMU_ARCH_RX)
 SRST
 ``-semihosting``
-    Enable semihosting mode (ARM, M68K, Xtensa, MIPS, Nios II, RISC-V only).
+    Enable semihosting mode
+    (Only ARM, M68K, Xtensa, MIPS, Nios II, RISC-V, RX).
 
     Note that this allows guest direct access to the host filesystem, so
     should only be used with a trusted guest OS.
@@ -4545,11 +4546,11 @@ DEF("semihosting-config", HAS_ARG, QEMU_OPTION_semihosting_config,
     "-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,arg=str[,...]]\n" \
     "                semihosting configuration\n",
 QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA |
-QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV)
+QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV | QEMU_ARCH_RX)
 SRST
 ``-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,arg=str[,...]]``
-    Enable and configure semihosting (ARM, M68K, Xtensa, MIPS, Nios II, RISC-V
-    only).
+    Enable and configure semihosting
+    (Only ARM, M68K, Xtensa, MIPS, Nios II, RISC-V, RX).
 
     Note that this allows guest direct access to the host filesystem, so
     should only be used with a trusted guest OS.
@@ -4557,7 +4558,7 @@ SRST
     On Arm this implements the standard semihosting API, version 2.0.
 
     On M68K this implements the "ColdFire GDB" interface used by
-    libgloss.
+    libgloss.  Nios II and RX also use the libgloss interface.
 
     Xtensa semihosting provides basic file IO calls, such as
     open/read/write/seek/select. Tensilica baremetal libc for ISS and
diff --git a/target/rx/meson.build b/target/rx/meson.build
index 8de0ad49b9..2eeac0c1b5 100644
--- a/target/rx/meson.build
+++ b/target/rx/meson.build
@@ -10,7 +10,9 @@ rx_ss.add(files(
   'helper.c',
   'cpu.c',
   'gdbstub.c',
-  'disas.c'))
+  'disas.c',
+  'rx-semi.c',
+))
 
 target_arch += {'rx': rx_ss}
 target_softmmu_arch += {'rx': ss.source_set()}
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* [PATCH v2 74/74] tests/tcg/rx: Enable semihosting multiarch tests
  2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
                   ` (72 preceding siblings ...)
  2022-05-03 19:48 ` [PATCH v2 73/74] target/rx: Implement libgloss semihosting Richard Henderson
@ 2022-05-03 19:48 ` Richard Henderson
  73 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-03 19:48 UTC (permalink / raw)
  To: qemu-devel

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 tests/tcg/rx/outc.c                  | 15 +++++++++++++++
 tests/tcg/rx/Makefile.softmmu-target | 24 ++++++++++++++++++++++++
 2 files changed, 39 insertions(+)
 create mode 100644 tests/tcg/rx/outc.c
 create mode 100644 tests/tcg/rx/Makefile.softmmu-target

diff --git a/tests/tcg/rx/outc.c b/tests/tcg/rx/outc.c
new file mode 100644
index 0000000000..3f8720d7ca
--- /dev/null
+++ b/tests/tcg/rx/outc.c
@@ -0,0 +1,15 @@
+/*
+ * minilib.h compatibility code
+ *
+ * Copyright Linaro Ltd 2022
+ *
+ * Rely on newlib/libgloss for functionality.
+ */
+
+#include "minilib.h"
+#include <sys/unistd.h>
+
+void __sys_outc(char c)
+{
+    write(1, &c, 1);
+}
diff --git a/tests/tcg/rx/Makefile.softmmu-target b/tests/tcg/rx/Makefile.softmmu-target
new file mode 100644
index 0000000000..aaa1cebb92
--- /dev/null
+++ b/tests/tcg/rx/Makefile.softmmu-target
@@ -0,0 +1,24 @@
+#
+# RX system tests
+#
+
+RX_SYSTEM_SRC = $(SRC_PATH)/tests/tcg/rx
+VPATH += $(RX_SYSTEM_SRC)
+
+TESTS += $(MULTIARCH_TESTS)
+
+CFLAGS += -Og -g $(MINILIB_INC)
+LDFLAGS += -msim
+
+MINILIB_OBJS += outc.o
+.PRECIOUS: $(MINILIB_OBJS)
+
+%.o: %.c
+	$(call quiet-command, $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c $< -o $@, CC, $@)
+
+%: %.o $(LINK_SCRIPT) $(MINILIB_OBJS)
+	$(call quiet-command, $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) $(MINILIB_OBJS), LD, $@)
+
+QEMU_OPTS = -M gdbsim-r5f562n7 -m 128 -semihosting-config enable=on,target=native,chardev=output -kernel
+
+memory: CFLAGS+=-DCHECK_UNALIGNED=0
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 92+ messages in thread

* Re: [PATCH v2 16/74] semihosting: Split is_64bit_semihosting per target
  2022-05-03 19:47 ` [PATCH v2 16/74] semihosting: Split is_64bit_semihosting per target Richard Henderson
@ 2022-05-04  8:58   ` Alistair Francis
  0 siblings, 0 replies; 92+ messages in thread
From: Alistair Francis @ 2022-05-04  8:58 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel@nongnu.org Developers

On Wed, May 4, 2022 at 6:11 AM Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> We already have some larger ifdef blocks for ARM and RISCV;
> split the function into multiple implementations per arch.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  semihosting/arm-compat-semi.c | 19 ++++++++-----------
>  1 file changed, 8 insertions(+), 11 deletions(-)
>
> diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
> index a6c6e5baf6..7fc60e223a 100644
> --- a/semihosting/arm-compat-semi.c
> +++ b/semihosting/arm-compat-semi.c
> @@ -213,6 +213,10 @@ common_semi_sys_exit_extended(CPUState *cs, int nr)
>      return (nr == TARGET_SYS_EXIT_EXTENDED || is_a64(cs->env_ptr));
>  }
>
> +static inline bool is_64bit_semihosting(CPUArchState *env)
> +{
> +    return is_a64(env);
> +}
>  #endif /* TARGET_ARM */
>
>  #ifdef TARGET_RISCV
> @@ -238,6 +242,10 @@ common_semi_sys_exit_extended(CPUState *cs, int nr)
>      return (nr == TARGET_SYS_EXIT_EXTENDED || sizeof(target_ulong) == 8);
>  }
>
> +static inline bool is_64bit_semihosting(CPUArchState *env)
> +{
> +    return riscv_cpu_mxl(env) != MXL_RV32;
> +}
>  #endif
>
>  /*
> @@ -586,17 +594,6 @@ static const GuestFDFunctions guestfd_fns[] = {
>   * call if the memory read fails. Eventually we could use a generic
>   * CPUState helper function here.
>   */
> -static inline bool is_64bit_semihosting(CPUArchState *env)
> -{
> -#if defined(TARGET_ARM)
> -    return is_a64(env);
> -#elif defined(TARGET_RISCV)
> -    return riscv_cpu_mxl(env) != MXL_RV32;
> -#else
> -#error un-handled architecture
> -#endif
> -}
> -
>
>  #define GET_ARG(n) do {                                 \
>      if (is_64bit_semihosting(env)) {                    \
> --
> 2.34.1
>
>


^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v2 17/74] semihosting: Split common_semi_flen_buf per target
  2022-05-03 19:47 ` [PATCH v2 17/74] semihosting: Split common_semi_flen_buf " Richard Henderson
@ 2022-05-04  8:59   ` Alistair Francis
  0 siblings, 0 replies; 92+ messages in thread
From: Alistair Francis @ 2022-05-04  8:59 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel@nongnu.org Developers

On Wed, May 4, 2022 at 5:59 AM Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> We already have some larger ifdef blocks for ARM and RISCV;
> split out common_semi_stack_bottom per target.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  semihosting/arm-compat-semi.c | 44 +++++++++++++++++------------------
>  1 file changed, 21 insertions(+), 23 deletions(-)
>
> diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
> index 7fc60e223a..b2816e9f66 100644
> --- a/semihosting/arm-compat-semi.c
> +++ b/semihosting/arm-compat-semi.c
> @@ -217,6 +217,13 @@ static inline bool is_64bit_semihosting(CPUArchState *env)
>  {
>      return is_a64(env);
>  }
> +
> +static inline target_ulong common_semi_stack_bottom(CPUState *cs)
> +{
> +    ARMCPU *cpu = ARM_CPU(cs);
> +    CPUARMState *env = &cpu->env;
> +    return is_a64(env) ? env->xregs[31] : env->regs[13];
> +}
>  #endif /* TARGET_ARM */
>
>  #ifdef TARGET_RISCV
> @@ -246,6 +253,13 @@ static inline bool is_64bit_semihosting(CPUArchState *env)
>  {
>      return riscv_cpu_mxl(env) != MXL_RV32;
>  }
> +
> +static inline target_ulong common_semi_stack_bottom(CPUState *cs)
> +{
> +    RISCVCPU *cpu = RISCV_CPU(cs);
> +    CPURISCVState *env = &cpu->env;
> +    return env->gpr[xSP];
> +}
>  #endif
>
>  /*
> @@ -301,31 +315,15 @@ static void common_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
>      common_semi_set_ret(cs, ret);
>  }
>
> +/*
> + * Return an address in target memory of 64 bytes where the remote
> + * gdb should write its stat struct. (The format of this structure
> + * is defined by GDB's remote protocol and is not target-specific.)
> + * We put this on the guest's stack just below SP.
> + */
>  static target_ulong common_semi_flen_buf(CPUState *cs)
>  {
> -    target_ulong sp;
> -#ifdef TARGET_ARM
> -    /* Return an address in target memory of 64 bytes where the remote
> -     * gdb should write its stat struct. (The format of this structure
> -     * is defined by GDB's remote protocol and is not target-specific.)
> -     * We put this on the guest's stack just below SP.
> -     */
> -    ARMCPU *cpu = ARM_CPU(cs);
> -    CPUARMState *env = &cpu->env;
> -
> -    if (is_a64(env)) {
> -        sp = env->xregs[31];
> -    } else {
> -        sp = env->regs[13];
> -    }
> -#endif
> -#ifdef TARGET_RISCV
> -    RISCVCPU *cpu = RISCV_CPU(cs);
> -    CPURISCVState *env = &cpu->env;
> -
> -    sp = env->gpr[xSP];
> -#endif
> -
> +    target_ulong sp = common_semi_stack_bottom(cs);
>      return sp - 64;
>  }
>
> --
> 2.34.1
>
>


^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v2 18/74] semihosting: Split out common_semi_has_synccache
  2022-05-03 19:47 ` [PATCH v2 18/74] semihosting: Split out common_semi_has_synccache Richard Henderson
@ 2022-05-04  9:01   ` Alistair Francis
  0 siblings, 0 replies; 92+ messages in thread
From: Alistair Francis @ 2022-05-04  9:01 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel@nongnu.org Developers

On Wed, May 4, 2022 at 6:02 AM Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> We already have some larger ifdef blocks for ARM and RISCV;
> split out a boolean test for SYS_SYNCCACHE.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  semihosting/arm-compat-semi.c | 20 +++++++++++++-------
>  1 file changed, 13 insertions(+), 7 deletions(-)
>
> diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
> index b2816e9f66..6149be404f 100644
> --- a/semihosting/arm-compat-semi.c
> +++ b/semihosting/arm-compat-semi.c
> @@ -224,6 +224,12 @@ static inline target_ulong common_semi_stack_bottom(CPUState *cs)
>      CPUARMState *env = &cpu->env;
>      return is_a64(env) ? env->xregs[31] : env->regs[13];
>  }
> +
> +static inline bool common_semi_has_synccache(CPUArchState *env)
> +{
> +    /* Invalid for A32/T32. */
> +    return !is_a64(env);
> +}
>  #endif /* TARGET_ARM */
>
>  #ifdef TARGET_RISCV
> @@ -260,6 +266,11 @@ static inline target_ulong common_semi_stack_bottom(CPUState *cs)
>      CPURISCVState *env = &cpu->env;
>      return env->gpr[xSP];
>  }
> +
> +static inline bool common_semi_has_synccache(CPUArchState *env)
> +{
> +    return true;
> +}
>  #endif
>
>  /*
> @@ -1103,16 +1114,11 @@ void do_common_semihosting(CPUState *cs)
>           * virtual address range. This is a nop for us since we don't
>           * implement caches. This is only present on A64.
>           */
> -#ifdef TARGET_ARM
> -        if (is_a64(cs->env_ptr)) {
> +        if (common_semi_has_synccache(env)) {
>              common_semi_set_ret(cs, 0);
>              break;
>          }
> -#endif
> -#ifdef TARGET_RISCV
> -        common_semi_set_ret(cs, 0);
> -#endif
> -        /* fall through -- invalid for A32/T32 */
> +        /* fall through */
>      default:
>          fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr);
>          cpu_dump_state(cs, stderr, 0);
> --
> 2.34.1
>
>


^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v2 68/74] hw/rx: Handle a kernel file that is ELF
  2022-05-03 19:48 ` [PATCH v2 68/74] hw/rx: Handle a kernel file that is ELF Richard Henderson
@ 2022-05-13 15:44   ` Peter Maydell
  2022-05-13 15:48     ` Richard Henderson
  0 siblings, 1 reply; 92+ messages in thread
From: Peter Maydell @ 2022-05-13 15:44 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel

On Tue, 3 May 2022 at 21:52, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> Attempt to load the kernel with load_elf.  If this fails with
> ELF_LOAD_NOT_ELF, continue to treat the kernel as a raw image.
>
> This will be handy for running semihosting programs.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

I know nothing of the specifics of the rx target, but I'm
always a bit dubious about adding more behaviour to the
-kernel option, which is (a) already a morass of undocumented
target specific behaviours (b) nominally supposed to be
"load a Linux kernel", not "load any random thing".
Can you do what you need with the generic-loader device instead?
That has the benefit of both being documented and also doing
the same thing on all target architectures.


thanks
-- PMM


^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v2 68/74] hw/rx: Handle a kernel file that is ELF
  2022-05-13 15:44   ` Peter Maydell
@ 2022-05-13 15:48     ` Richard Henderson
  2022-05-13 16:40       ` Richard Henderson
  0 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2022-05-13 15:48 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-devel

On 5/13/22 08:44, Peter Maydell wrote:
> On Tue, 3 May 2022 at 21:52, Richard Henderson
> <richard.henderson@linaro.org> wrote:
>>
>> Attempt to load the kernel with load_elf.  If this fails with
>> ELF_LOAD_NOT_ELF, continue to treat the kernel as a raw image.
>>
>> This will be handy for running semihosting programs.
>>
>> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> 
> I know nothing of the specifics of the rx target, but I'm
> always a bit dubious about adding more behaviour to the
> -kernel option, which is (a) already a morass of undocumented
> target specific behaviours (b) nominally supposed to be
> "load a Linux kernel", not "load any random thing".
> Can you do what you need with the generic-loader device instead?
> That has the benefit of both being documented and also doing
> the same thing on all target architectures.

I'll give that a try.


r~


^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v2 68/74] hw/rx: Handle a kernel file that is ELF
  2022-05-13 15:48     ` Richard Henderson
@ 2022-05-13 16:40       ` Richard Henderson
  0 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-13 16:40 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-devel, Alex Bennée

On 5/13/22 08:48, Richard Henderson wrote:
> On 5/13/22 08:44, Peter Maydell wrote:
>> On Tue, 3 May 2022 at 21:52, Richard Henderson
>> <richard.henderson@linaro.org> wrote:
>>>
>>> Attempt to load the kernel with load_elf.  If this fails with
>>> ELF_LOAD_NOT_ELF, continue to treat the kernel as a raw image.
>>>
>>> This will be handy for running semihosting programs.
>>>
>>> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>>
>> I know nothing of the specifics of the rx target, but I'm
>> always a bit dubious about adding more behaviour to the
>> -kernel option, which is (a) already a morass of undocumented
>> target specific behaviours (b) nominally supposed to be
>> "load a Linux kernel", not "load any random thing".
>> Can you do what you need with the generic-loader device instead?
>> That has the benefit of both being documented and also doing
>> the same thing on all target architectures.
> 
> I'll give that a try.

It works, editing the board not to reject lack of -bios and lack of -kernel.  And running 
by hand because the syntax of the test harness does not allow the test file to be joined 
with $(QEMU_OPTS), as in

   -device loader,cpu-num=0,file=testcase

I'll work with Alex to figure out how best to restructure the test harness.

In the meantime I certainly don't mind putting the rx part on the back burner if it'll 
help get the previous 67 patches reviewed...


r~


^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v2 01/74] semihosting: Move exec/softmmu-semi.h to semihosting/softmmu-uaccess.h
  2022-05-03 19:47 ` [PATCH v2 01/74] semihosting: Move exec/softmmu-semi.h to semihosting/softmmu-uaccess.h Richard Henderson
@ 2022-05-16 14:36   ` Peter Maydell
  0 siblings, 0 replies; 92+ messages in thread
From: Peter Maydell @ 2022-05-16 14:36 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel

On Tue, 3 May 2022 at 20:53, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> We have a subdirectory for semihosting; move this file out of exec.
> Rename to emphasize the contents are a replacement for the functions
> in linux-user/bsd-user uaccess.c.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM


^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v2 02/74] semihosting: Return failure from softmmu-uaccess.h functions
  2022-05-03 19:47 ` [PATCH v2 02/74] semihosting: Return failure from softmmu-uaccess.h functions Richard Henderson
@ 2022-05-16 14:42   ` Peter Maydell
  0 siblings, 0 replies; 92+ messages in thread
From: Peter Maydell @ 2022-05-16 14:42 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel

On Tue, 3 May 2022 at 20:53, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> We were reporting unconditional success for these functions;
> pass on any failure from cpu_memory_rw_debug.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM


^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v2 03/74] semihosting: Improve condition for config.c and console.c
  2022-05-03 19:47 ` [PATCH v2 03/74] semihosting: Improve condition for config.c and console.c Richard Henderson
@ 2022-05-16 15:00   ` Peter Maydell
  0 siblings, 0 replies; 92+ messages in thread
From: Peter Maydell @ 2022-05-16 15:00 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel

On Tue, 3 May 2022 at 20:57, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> While CONFIG_SEMIHOSTING is currently only set for softmmu,
> this will not continue to be true.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  semihosting/meson.build | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM


^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v2 04/74] semihosting: Move softmmu-uaccess.h functions out of line
  2022-05-03 19:47 ` [PATCH v2 04/74] semihosting: Move softmmu-uaccess.h functions out of line Richard Henderson
@ 2022-05-16 15:04   ` Peter Maydell
  0 siblings, 0 replies; 92+ messages in thread
From: Peter Maydell @ 2022-05-16 15:04 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel

On Tue, 3 May 2022 at 20:59, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> Rather that static (and not even inline) functions within a
> header, move the functions to semihosting/uaccess.c.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM


^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v2 05/74] semihosting: Add target_strlen for softmmu-uaccess.h
  2022-05-03 19:47 ` [PATCH v2 05/74] semihosting: Add target_strlen for softmmu-uaccess.h Richard Henderson
@ 2022-05-16 15:11   ` Peter Maydell
  2022-05-17  1:33     ` Richard Henderson
  0 siblings, 1 reply; 92+ messages in thread
From: Peter Maydell @ 2022-05-16 15:11 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel

On Tue, 3 May 2022 at 20:57, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> Mirror the user-only function of the same name.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  include/semihosting/softmmu-uaccess.h |  3 +++
>  semihosting/uaccess.c                 | 29 +++++++++++++++++++++++++++
>  2 files changed, 32 insertions(+)
>
> diff --git a/include/semihosting/softmmu-uaccess.h b/include/semihosting/softmmu-uaccess.h
> index 03300376d3..4f08dfc098 100644
> --- a/include/semihosting/softmmu-uaccess.h
> +++ b/include/semihosting/softmmu-uaccess.h
> @@ -53,4 +53,7 @@ void softmmu_unlock_user(CPUArchState *env, void *p,
>                           target_ulong addr, target_ulong len);
>  #define unlock_user(s, args, len) softmmu_unlock_user(env, s, args, len)
>
> +ssize_t softmmu_strlen_user(CPUArchState *env, target_ulong addr);
> +#define target_strlen(p) softmmu_strlen_user(env, p)
> +
>  #endif /* SEMIHOSTING_SOFTMMU_UACCESS_H */
> diff --git a/semihosting/uaccess.c b/semihosting/uaccess.c
> index 0d3b32b75d..3cd809122c 100644
> --- a/semihosting/uaccess.c
> +++ b/semihosting/uaccess.c
> @@ -23,6 +23,35 @@ void *softmmu_lock_user(CPUArchState *env, target_ulong addr,
>      return p;
>  }
>
> +ssize_t softmmu_strlen_user(CPUArchState *env, target_ulong addr)
> +{
> +    char buf[256];
> +    size_t len = 0;
> +
> +    while (1) {
> +        size_t chunk;
> +        char *p;
> +
> +        chunk = -(addr | TARGET_PAGE_MASK);

'chunk' is unsigned but we're assigning it a negative number here...
I assume this is doing some clever bit-twiddling trick but it isn't
very obvious.

In any case, rounding to a page boundary isn't sufficient to
avoid problems, because we don't mandate that RAM-to-device
MemoryRegion boundaries happen on page boundaries. I think you
either need to do this at a low enough level that you can
look at what MemoryRegion types you're reading from, or you need
to do it byte at a time.

> +        chunk = MIN(chunk, sizeof(buf));
> +
> +        if (cpu_memory_rw_debug(env_cpu(env), addr, buf, chunk, 0)) {
> +            return -1;
> +        }
> +        p = memchr(buf, 0, chunk);
> +        if (p) {
> +            len += p - buf;
> +            return len <= INT32_MAX ? (ssize_t)len : -1;
> +        }
> +
> +        len += chunk;
> +        addr += chunk;
> +        if (len > INT32_MAX) {
> +            return -1;
> +        }
> +    }
> +}

thanks
-- PMM


^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v2 06/74] semihosting: Simplify softmmu_lock_user_string
  2022-05-03 19:47 ` [PATCH v2 06/74] semihosting: Simplify softmmu_lock_user_string Richard Henderson
@ 2022-05-16 15:12   ` Peter Maydell
  0 siblings, 0 replies; 92+ messages in thread
From: Peter Maydell @ 2022-05-16 15:12 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel

On Tue, 3 May 2022 at 21:05, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> We are not currently bounding the search to the 1024 bytes
> that we allocated, possibly overrunning the buffer.
> Use softmmu_strlen_user to find the length and allocate the
> correct size from the beginning.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM


^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v2 07/74] semihosting: Split out guestfd.c
  2022-05-03 19:47 ` [PATCH v2 07/74] semihosting: Split out guestfd.c Richard Henderson
@ 2022-05-16 15:14   ` Peter Maydell
  2022-05-17  1:47     ` Richard Henderson
  0 siblings, 1 reply; 92+ messages in thread
From: Peter Maydell @ 2022-05-16 15:14 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel

On Tue, 3 May 2022 at 21:02, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> In arm-compat-semi.c, we have more advanced treatment of
> guest file descriptors than we do in other implementations.
> Split out GuestFD and related functions to a new file so
> that they can be shared.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  configs/targets/aarch64-linux-user.mak    |   1 +
>  configs/targets/aarch64_be-linux-user.mak |   1 +
>  configs/targets/arm-linux-user.mak        |   1 +
>  configs/targets/armeb-linux-user.mak      |   1 +
>  configs/targets/riscv32-linux-user.mak    |   1 +
>  configs/targets/riscv64-linux-user.mak    |   1 +
>  include/semihosting/guestfd.h             |  40 +++++++
>  semihosting/arm-compat-semi.c             | 125 +---------------------
>  semihosting/guestfd.c                     | 116 ++++++++++++++++++++
>  semihosting/meson.build                   |   4 +
>  10 files changed, 168 insertions(+), 123 deletions(-)
>  create mode 100644 include/semihosting/guestfd.h
>  create mode 100644 semihosting/guestfd.c
>
> diff --git a/configs/targets/aarch64-linux-user.mak b/configs/targets/aarch64-linux-user.mak
> index d0c603c54e..db552f1839 100644
> --- a/configs/targets/aarch64-linux-user.mak
> +++ b/configs/targets/aarch64-linux-user.mak
> @@ -2,4 +2,5 @@ TARGET_ARCH=aarch64
>  TARGET_BASE_ARCH=arm
>  TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml
>  TARGET_HAS_BFLT=y
> +CONFIG_SEMIHOSTING=y
>  CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y

Is it not possible to make CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
imply CONFIG_SEMIHOSTING=y somehow?


> --- /dev/null
> +++ b/include/semihosting/guestfd.h
> @@ -0,0 +1,40 @@
> +/*
> + * Hosted file support for semihosting syscalls.
> + *
> + * Copyright (c) 2005, 2007 CodeSourcery.
> + * Copyright (c) 2019 Linaro
> + * Copyright © 2020 by Keith Packard <keithp@keithp.com>
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#ifndef SEMIHOSTING_GUESTFD_H
> +#define SEMIHOSTING_GUESTFD_H
> +
> +typedef enum GuestFDType {
> +    GuestFDUnused = 0,
> +    GuestFDHost = 1,
> +    GuestFDGDB = 2,
> +    GuestFDFeatureFile = 3,
> +} GuestFDType;
> +
> +/*
> + * Guest file descriptors are integer indexes into an array of
> + * these structures (we will dynamically resize as necessary).
> + */
> +typedef struct GuestFD {
> +    GuestFDType type;
> +    union {
> +        int hostfd;
> +        unsigned featurefile_offset;
> +    };
> +} GuestFD;
> +
> +int alloc_guestfd(void);
> +void dealloc_guestfd(int guestfd);
> +GuestFD *get_guestfd(int guestfd);
> +
> +void associate_guestfd(int guestfd, int hostfd);
> +void init_featurefile_guestfd(int guestfd);

If these are moving from being static functions local to a file
to being global, they should get kerneldoc style doc-comments here in
the header file.

thanks
-- PMM


^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v2 08/74] semihosting: Generalize GuestFDFeatureFile
  2022-05-03 19:47 ` [PATCH v2 08/74] semihosting: Generalize GuestFDFeatureFile Richard Henderson
@ 2022-05-16 15:20   ` Peter Maydell
  0 siblings, 0 replies; 92+ messages in thread
From: Peter Maydell @ 2022-05-16 15:20 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel

On Tue, 3 May 2022 at 21:08, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> Rather than hard-coding the buffer from which we deliver data,
> pass it in on initialization.  This decouples the feature from
> ARM semihosting.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM


^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v2 09/74] semihosting: Return void from do_common_semihosting
  2022-05-03 19:47 ` [PATCH v2 09/74] semihosting: Return void from do_common_semihosting Richard Henderson
@ 2022-05-16 15:31   ` Peter Maydell
  0 siblings, 0 replies; 92+ messages in thread
From: Peter Maydell @ 2022-05-16 15:31 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel

On Tue, 3 May 2022 at 20:58, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> Perform the cleanup in the FIXME comment in common_semi_gdb_syscall.
> Do not modify guest registers until the syscall is complete,
> which in the gdbstub case is asynchronous.
>
> In the synchronous non-gdbstub case, use common_semi_set_ret
> to set the result.  Merge set_swi_errno into common_semi_cb.
> Rely on the latter for combined return value / errno setting.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  semihosting/common-semi.h     |   2 +-
>  linux-user/aarch64/cpu_loop.c |   2 +-
>  linux-user/arm/cpu_loop.c     |   2 +-
>  linux-user/riscv/cpu_loop.c   |   2 +-
>  semihosting/arm-compat-semi.c | 571 ++++++++++++++++------------------
>  target/arm/helper.c           |   4 +-
>  target/arm/m_helper.c         |   2 +-
>  target/riscv/cpu_helper.c     |   2 +-
>  8 files changed, 278 insertions(+), 309 deletions(-)

Oof, this is a big patch. I get that to some extent the
switch from "return the x0 value for callers to set" to
"leaf functions set x0, everything returns void" has to
be done as one patch. But for instance this bit:

> -static inline uint32_t set_swi_errno(CPUState *cs, uint32_t code)
> -{
> -    if (code == (uint32_t)-1) {
> -#ifdef CONFIG_USER_ONLY
> -        TaskState *ts = cs->opaque;
> -
> -        ts->swi_errno = errno;
> -#else
> -        syscall_err = errno;
> -#endif
> -    }
> -    return code;
> -}
> -
>  static inline uint32_t get_swi_errno(CPUState *cs)
>  {
>  #ifdef CONFIG_USER_ONLY
> @@ -290,28 +276,29 @@ static target_ulong common_semi_syscall_len;
>
>  static void common_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
>  {
> -    target_ulong reg0 = common_semi_arg(cs, 0);
> -
>      if (ret == (target_ulong)-1) {
> -        errno = err;
> -        set_swi_errno(cs, -1);
> -        reg0 = ret;
> +#ifdef CONFIG_USER_ONLY
> +        TaskState *ts = cs->opaque;
> +        ts->swi_errno = err;
> +#else
> +        syscall_err = err;
> +#endif
>      } else {
>          /* Fixup syscalls that use nonstardard return conventions.  */
> +        target_ulong reg0 = common_semi_arg(cs, 0);
>          switch (reg0) {
>          case TARGET_SYS_WRITE:
>          case TARGET_SYS_READ:
> -            reg0 = common_semi_syscall_len - ret;
> +            ret = common_semi_syscall_len - ret;
>              break;
>          case TARGET_SYS_SEEK:
> -            reg0 = 0;
> +            ret = 0;
>              break;
>          default:
> -            reg0 = ret;
>              break;
>          }
>      }
> -    common_semi_set_ret(cs, reg0);
> +    common_semi_set_ret(cs, ret);
>  }

seems like it's just inlining a function, renaming a variable,
moving the point where we initialize it around a little.
That could be its own patch, right?

thanks
-- PMM


^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v2 05/74] semihosting: Add target_strlen for softmmu-uaccess.h
  2022-05-16 15:11   ` Peter Maydell
@ 2022-05-17  1:33     ` Richard Henderson
  0 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-17  1:33 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-devel

On 5/16/22 08:11, Peter Maydell wrote:
>> +        chunk = -(addr | TARGET_PAGE_MASK);
> 
> 'chunk' is unsigned but we're assigning it a negative number here...
> I assume this is doing some clever bit-twiddling trick but it isn't
> very obvious.

Number of bytes left in page -- I'll rename the variable.

> In any case, rounding to a page boundary isn't sufficient to
> avoid problems, because we don't mandate that RAM-to-device
> MemoryRegion boundaries happen on page boundaries. I think you
> either need to do this at a low enough level that you can
> look at what MemoryRegion types you're reading from, or you need
> to do it byte at a time.

Easy enough to use probe_access_flags.


r~


^ permalink raw reply	[flat|nested] 92+ messages in thread

* Re: [PATCH v2 07/74] semihosting: Split out guestfd.c
  2022-05-16 15:14   ` Peter Maydell
@ 2022-05-17  1:47     ` Richard Henderson
  0 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2022-05-17  1:47 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-devel

On 5/16/22 08:14, Peter Maydell wrote:
>> diff --git a/configs/targets/aarch64-linux-user.mak b/configs/targets/aarch64-linux-user.mak
>> index d0c603c54e..db552f1839 100644
>> --- a/configs/targets/aarch64-linux-user.mak
>> +++ b/configs/targets/aarch64-linux-user.mak
>> @@ -2,4 +2,5 @@ TARGET_ARCH=aarch64
>>   TARGET_BASE_ARCH=arm
>>   TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml
>>   TARGET_HAS_BFLT=y
>> +CONFIG_SEMIHOSTING=y
>>   CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
> 
> Is it not possible to make CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
> imply CONFIG_SEMIHOSTING=y somehow?

I don't think so -- Kconfig is only processed for softmmu.

> If these are moving from being static functions local to a file
> to being global, they should get kerneldoc style doc-comments here in
> the header file.

Ok.

r~


^ permalink raw reply	[flat|nested] 92+ messages in thread

end of thread, other threads:[~2022-05-17  1:48 UTC | newest]

Thread overview: 92+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-05-03 19:47 [PATCH v2 00/74] semihosting cleanup Richard Henderson
2022-05-03 19:47 ` [PATCH v2 01/74] semihosting: Move exec/softmmu-semi.h to semihosting/softmmu-uaccess.h Richard Henderson
2022-05-16 14:36   ` Peter Maydell
2022-05-03 19:47 ` [PATCH v2 02/74] semihosting: Return failure from softmmu-uaccess.h functions Richard Henderson
2022-05-16 14:42   ` Peter Maydell
2022-05-03 19:47 ` [PATCH v2 03/74] semihosting: Improve condition for config.c and console.c Richard Henderson
2022-05-16 15:00   ` Peter Maydell
2022-05-03 19:47 ` [PATCH v2 04/74] semihosting: Move softmmu-uaccess.h functions out of line Richard Henderson
2022-05-16 15:04   ` Peter Maydell
2022-05-03 19:47 ` [PATCH v2 05/74] semihosting: Add target_strlen for softmmu-uaccess.h Richard Henderson
2022-05-16 15:11   ` Peter Maydell
2022-05-17  1:33     ` Richard Henderson
2022-05-03 19:47 ` [PATCH v2 06/74] semihosting: Simplify softmmu_lock_user_string Richard Henderson
2022-05-16 15:12   ` Peter Maydell
2022-05-03 19:47 ` [PATCH v2 07/74] semihosting: Split out guestfd.c Richard Henderson
2022-05-16 15:14   ` Peter Maydell
2022-05-17  1:47     ` Richard Henderson
2022-05-03 19:47 ` [PATCH v2 08/74] semihosting: Generalize GuestFDFeatureFile Richard Henderson
2022-05-16 15:20   ` Peter Maydell
2022-05-03 19:47 ` [PATCH v2 09/74] semihosting: Return void from do_common_semihosting Richard Henderson
2022-05-16 15:31   ` Peter Maydell
2022-05-03 19:47 ` [PATCH v2 10/74] semihosting: Adjust error checking in common_semi_cb Richard Henderson
2022-05-03 19:47 ` [PATCH v2 11/74] semihosting: Move common-semi.h to include/semihosting/ Richard Henderson
2022-05-03 19:47 ` [PATCH v2 12/74] include/exec: Move gdb open flags to gdbstub.h Richard Henderson
2022-05-03 19:47 ` [PATCH v2 13/74] include/exec: Move gdb_stat and gdb_timeval " Richard Henderson
2022-05-03 19:47 ` [PATCH v2 14/74] include/exec: Define errno values in gdbstub.h Richard Henderson
2022-05-03 19:47 ` [PATCH v2 15/74] semihosting: Use struct gdb_stat in common_semi_flen_cb Richard Henderson
2022-05-03 19:47 ` [PATCH v2 16/74] semihosting: Split is_64bit_semihosting per target Richard Henderson
2022-05-04  8:58   ` Alistair Francis
2022-05-03 19:47 ` [PATCH v2 17/74] semihosting: Split common_semi_flen_buf " Richard Henderson
2022-05-04  8:59   ` Alistair Francis
2022-05-03 19:47 ` [PATCH v2 18/74] semihosting: Split out common_semi_has_synccache Richard Henderson
2022-05-04  9:01   ` Alistair Francis
2022-05-03 19:47 ` [PATCH v2 19/74] semihosting: Use env more often in do_common_semihosting Richard Henderson
2022-05-03 19:47 ` [PATCH v2 20/74] semihosting: Move GET_ARG/SET_ARG earlier in the file Richard Henderson
2022-05-03 19:47 ` [PATCH v2 21/74] semihosting: Split out semihost_sys_open Richard Henderson
2022-05-03 19:47 ` [PATCH v2 22/74] semihosting: Split out semihost_sys_close Richard Henderson
2022-05-03 19:47 ` [PATCH v2 23/74] semihosting: Split out semihost_sys_read Richard Henderson
2022-05-03 19:47 ` [PATCH v2 24/74] semihosting: Split out semihost_sys_write Richard Henderson
2022-05-03 19:47 ` [PATCH v2 25/74] semihosting: Bound length for semihost_sys_{read, write} Richard Henderson
2022-05-03 19:47 ` [PATCH v2 26/74] semihosting: Split out semihost_sys_lseek Richard Henderson
2022-05-03 19:47 ` [PATCH v2 27/74] semihosting: Split out semihost_sys_isatty Richard Henderson
2022-05-03 19:47 ` [PATCH v2 28/74] semihosting: Split out semihost_sys_flen Richard Henderson
2022-05-03 19:47 ` [PATCH v2 29/74] semihosting: Split out semihost_sys_remove Richard Henderson
2022-05-03 19:47 ` [PATCH v2 30/74] semihosting: Split out semihost_sys_rename Richard Henderson
2022-05-03 19:48 ` [PATCH v2 31/74] semihosting: Split out semihost_sys_system Richard Henderson
2022-05-03 19:48 ` [PATCH v2 32/74] semihosting: Create semihost_sys_{stat,fstat} Richard Henderson
2022-05-03 19:48 ` [PATCH v2 33/74] semihosting: Create semihost_sys_gettimeofday Richard Henderson
2022-05-03 19:48 ` [PATCH v2 34/74] gdbstub: Widen gdb_syscall_complete_cb return value Richard Henderson
2022-05-03 19:48 ` [PATCH v2 35/74] semihosting: Fix docs comment for qemu_semihosting_console_inc Richard Henderson
2022-05-03 19:48 ` [PATCH v2 36/74] semihosting: Pass CPUState to qemu_semihosting_console_inc Richard Henderson
2022-05-03 19:48 ` [PATCH v2 37/74] semihosting: Expand qemu_semihosting_console_inc to read Richard Henderson
2022-05-03 19:48 ` [PATCH v2 38/74] semihosting: Cleanup chardev init Richard Henderson
2022-05-03 19:48 ` [PATCH v2 39/74] semihosting: Create qemu_semihosting_console_write Richard Henderson
2022-05-03 19:48 ` [PATCH v2 40/74] semihosting: Add GuestFDConsole Richard Henderson
2022-05-03 19:48 ` [PATCH v2 41/74] semihosting: Create qemu_semihosting_guestfd_init Richard Henderson
2022-05-03 19:48 ` [PATCH v2 42/74] semihosting: Use console_in_gf for SYS_READC Richard Henderson
2022-05-03 19:48 ` [PATCH v2 43/74] semihosting: Use console_out_gf for SYS_WRITEC Richard Henderson
2022-05-03 19:48 ` [PATCH v2 44/74] semihosting: Remove qemu_semihosting_console_outc Richard Henderson
2022-05-03 19:48 ` [PATCH v2 45/74] semihosting: Use console_out_gf for SYS_WRITE0 Richard Henderson
2022-05-03 19:48 ` [PATCH v2 46/74] semihosting: Remove qemu_semihosting_console_outs Richard Henderson
2022-05-03 19:48 ` [PATCH v2 47/74] semihosting: Create semihost_sys_poll_one Richard Henderson
2022-05-03 19:48 ` [PATCH v2 48/74] target/m68k: Eliminate m68k_semi_is_fseek Richard Henderson
2022-05-03 19:48 ` [PATCH v2 49/74] target/m68k: Make semihosting system only Richard Henderson
2022-05-03 19:48 ` [PATCH v2 50/74] target/m68k: Use semihosting/syscalls.h Richard Henderson
2022-05-03 19:48 ` [PATCH v2 51/74] target/nios2: Eliminate nios2_semi_is_lseek Richard Henderson
2022-05-03 19:48 ` [PATCH v2 52/74] target/nios2: Move nios2-semi.c to nios2_softmmu_ss Richard Henderson
2022-05-03 19:48 ` [PATCH v2 53/74] target/nios2: Use semihosting/syscalls.h Richard Henderson
2022-05-03 19:48 ` [PATCH v2 54/74] target/mips: Use an exception for semihosting Richard Henderson
2022-05-03 19:48 ` [PATCH v2 55/74] target/mips: Add UHI errno values Richard Henderson
2022-05-03 19:48 ` [PATCH v2 56/74] target/mips: Create report_fault for semihosting Richard Henderson
2022-05-03 19:48 ` [PATCH v2 57/74] target/mips: Drop link syscall from semihosting Richard Henderson
2022-05-03 19:48 ` [PATCH v2 58/74] target/mips: Drop pread and pwrite syscalls " Richard Henderson
2022-05-03 19:48 ` [PATCH v2 59/74] target/mips: Use semihosting/syscalls.h Richard Henderson
2022-05-03 19:48 ` [PATCH v2 60/74] target/mips: Avoid qemu_semihosting_log_out for UHI_plog Richard Henderson
2022-05-03 19:48 ` [PATCH v2 61/74] target/mips: Use error_report for UHI_assert Richard Henderson
2022-05-03 19:48 ` [PATCH v2 62/74] semihosting: Remove qemu_semihosting_log_out Richard Henderson
2022-05-03 19:48 ` [PATCH v2 63/74] target/mips: Simplify UHI_argnlen and UHI_argn Richard Henderson
2022-05-03 19:48 ` [PATCH v2 64/74] target/mips: Remove GET_TARGET_STRING and FREE_TARGET_STRING Richard Henderson
2022-05-03 19:48 ` [PATCH v2 65/74] target/xtensa: Use an exception for semihosting Richard Henderson
2022-05-03 19:48 ` [PATCH v2 66/74] target/xtensa: Use semihosting/syscalls.h Richard Henderson
2022-05-03 19:48 ` [PATCH v2 67/74] tests/docker: Add debian-rx-cross image Richard Henderson
2022-05-03 19:48 ` [PATCH v2 68/74] hw/rx: Handle a kernel file that is ELF Richard Henderson
2022-05-13 15:44   ` Peter Maydell
2022-05-13 15:48     ` Richard Henderson
2022-05-13 16:40       ` Richard Henderson
2022-05-03 19:48 ` [PATCH v2 69/74] target/rx: Fix the base of the fixed vector table Richard Henderson
2022-05-03 19:48 ` [PATCH v2 70/74] target/rx: Name the exceptions Richard Henderson
2022-05-03 19:48 ` [PATCH v2 71/74] target/rx: Consolidate exception helpers Richard Henderson
2022-05-03 19:48 ` [PATCH v2 72/74] target/rx: Cleanup rx_cpu_do_interrupt Richard Henderson
2022-05-03 19:48 ` [PATCH v2 73/74] target/rx: Implement libgloss semihosting Richard Henderson
2022-05-03 19:48 ` [PATCH v2 74/74] tests/tcg/rx: Enable semihosting multiarch tests Richard Henderson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.