All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/14] hexagon: add semihosting support
@ 2026-07-16 18:06 Matheus Tavares Bernardino
  2026-07-16 18:06 ` [PATCH v2 01/14] target/hexagon: fix improper assign of cause code to exception index Matheus Tavares Bernardino
                   ` (13 more replies)
  0 siblings, 14 replies; 19+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-16 18:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: brian.cain, pierrick.bouvier, marco.liebel, philmd, ale, anjo

This series adds semihosting support to hexagon system emulation,
together with functional tests for the added operations.

The Hexagon semihosting spec can be found at:
https://docs.qualcomm.com/doc/80-N2040-101_102648/topic/semihosting-specification.html

v1: https://lore.kernel.org/qemu-devel/cover.1783973054.git.matheus.bernardino@oss.qualcomm.com/

Changes in v2:
- Added patch 1, a fix for an existing bug that appeared with the new
  test semantics from the last patch.
- Patch 3: s/hexagon_touch_memory/hexagon_peek_memory_range/
- Patch 7:
  * Add semihosting spec link to docs
  * Fixed HEX_SYS_EXCEPTION
- Patch 10:
  * Moved tables to static definition
  * Fixed compilation for Windows
- Dropped patch 11 (OPEN/READ/CLOSE_DIR support): for now we don't have
  dirent semantics for Windows, so leave these ops to a followup series.
- Patch 14:
  * Update test version
  * Don't change directory
  * Don't use os.path, use scratch_file

Brian Cain (4):
  semihosting: add APIs for chardev-aware guest fd routing
  target/hexagon: Add an errno mapping
  python/machine: support routing semihosting output to the test console
  tests/functional: Add hexagon semihosting systests

Matheus Tavares Bernardino (10):
  target/hexagon: fix improper assign of cause code to exception index
  target/hexagon: fix get_phys_addr_debug with in-page offset
  target/hexagon: fix PC advancement for non-COF TB terminators
  target/hexagon: add aux functions for guest mem load/store
  hexagon: cpu_helper: add reg reading/writing helpers
  semihosting: add callback to set error
  target/hexagon: add semihosting support
  semihosting: add ftruncate helper (to be used for hexagon)
  target/hexagon: add main arch-specific semihosting operations
  target/hexagon: add COREDUMP semihosting operation

 docs/system/target-hexagon.rst            |   8 +-
 configs/targets/hexagon-softmmu.mak       |   2 +
 include/semihosting/common-semi.h         |   2 +
 include/semihosting/console.h             |   9 +
 include/semihosting/guestfd.h             |   9 +
 include/semihosting/syscalls.h            |   2 +
 target/hexagon/cpu_helper.h               |  24 +
 target/hexagon/internal.h                 |   1 +
 hw/hexagon/hexagon_dsp.c                  |   2 +
 semihosting/arm-compat-semi.c             |   3 +-
 semihosting/console.c                     |   5 +
 semihosting/guestfd.c                     |   8 +
 semihosting/syscalls.c                    |  29 +
 target/arm/common-semi-target.c           |   4 +
 target/hexagon/common-semi-target.c       |  51 ++
 target/hexagon/cpu.c                      |   7 +-
 target/hexagon/cpu_helper.c               | 173 ++++++
 target/hexagon/hexswi.c                   | 657 +++++++++++++++++++++-
 target/hexagon/op_helper.c                |  18 +-
 target/hexagon/translate.c                |  17 +-
 target/riscv/common-semi-target.c         |   4 +
 hw/hexagon/Kconfig                        |   1 +
 python/qemu/machine/machine.py            |  10 +-
 qemu-options.hx                           |   8 +-
 target/hexagon/meson.build                |   3 +
 tests/functional/hexagon/meson.build      |   9 +
 tests/functional/hexagon/test_systests.py | 110 ++++
 tests/functional/meson.build              |   1 +
 28 files changed, 1142 insertions(+), 35 deletions(-)
 create mode 100644 target/hexagon/common-semi-target.c
 create mode 100644 tests/functional/hexagon/meson.build
 create mode 100755 tests/functional/hexagon/test_systests.py

Range-diff against v1:
 -:  ----------- >  1:  aaac9492e5a target/hexagon: fix improper assign of cause code to exception index
 1:  dd52bfe14af !  2:  2f5247200ec target/hexagon: fix get_phys_addr_debug with in-page offset
    @@ Commit message
     
         This would break semihosting argument reads when it is added for Hexagon.
     
    +    Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
         Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
     
      ## target/hexagon/cpu.c ##
 2:  c0cc9ab4c7d !  3:  2cac81d1782 target/hexagon: fix PC advancement for non-COF TB terminators
    @@ Commit message
         hex_gpr[HEX_REG_PC]).  Drop the special case so these packets advance to
         the following packet like any other non-COF TB terminator.
     
    +    Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
         Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
     
      ## target/hexagon/translate.c ##
 3:  9cdc7c7f27a !  4:  b0f794c467a target/hexagon: add aux functions for guest mem load/store
    @@
      ## Metadata ##
    -Author: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
    +Author: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
     
      ## Commit message ##
         target/hexagon: add aux functions for guest mem load/store
     
         Will be used for semihosting.
     
    -    Signed-off-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
    +    Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
         Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
    +    Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
     
      ## target/hexagon/cpu_helper.h ##
     @@
    @@ target/hexagon/cpu_helper.h
     +                         void *retptr, uintptr_t retaddr);
     +void hexagon_write_memory(CPUHexagonState *env, target_ulong vaddr,
     +                          int size, uint64_t data, uintptr_t retaddr);
    -+void hexagon_touch_memory(CPUHexagonState *env, uint32_t start_addr,
    -+                          uint32_t length, uintptr_t retaddr);
    ++void hexagon_peek_memory_range(CPUHexagonState *env, uint32_t start_addr,
    ++                               uint32_t length, uintptr_t retaddr);
      uint32_t hexagon_get_pmu_counter(CPUHexagonState *cur_env, int index);
      void hexagon_modify_ssr(CPUHexagonState *env, uint32_t new, uint32_t old);
      int get_cpu_mode(CPUHexagonState *env);
    @@ target/hexagon/cpu_helper.c
     +    return addr & page_align;
     +}
     +
    -+void hexagon_touch_memory(CPUHexagonState *env, uint32_t start_addr,
    -+                          uint32_t length, uintptr_t retaddr)
    ++void hexagon_peek_memory_range(CPUHexagonState *env, uint32_t start_addr,
    ++                               uint32_t length, uintptr_t retaddr)
     +{
     +    unsigned int warm;
     +    uint32_t first = page_start(start_addr);
 4:  636d47e381c !  5:  5b16ff40a6e hexagon: cpu_helper: add reg reading/writing helpers
    @@ Commit message
         And adjust op_helper to use those. They will also be used on upcoming
         semihosting commits.
     
    +    Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
         Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
     
      ## target/hexagon/cpu_helper.h ##
 6:  726a2186349 !  6:  90074658cf5 semihosting: add APIs for chardev-aware guest fd routing
    @@ Commit message
         rather than directly to host stdio.
     
         Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
    +    Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
     
      ## include/semihosting/console.h ##
     @@ include/semihosting/console.h: void qemu_semihosting_console_block_until_ready(CPUState *cs);
 5:  df1607f5ee3 !  7:  a08d1e274e7 semihosting: add callback to set error
    @@ Commit message
         semihosting: add callback to set error
     
         This is currently unused by existing semihosting targets, but it will be
    -    used by hexagon.
    +    used by hexagon in the following commit.
     
    -    Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
         Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
    +    Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
    +    Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
     
      ## include/semihosting/common-semi.h ##
     @@
 7:  e01b8e57d6b !  8:  5c5c06f35f7 target/hexagon: add semihosting support
    @@
      ## Metadata ##
    -Author: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
    +Author: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
     
      ## Commit message ##
         target/hexagon: add semihosting support
    @@ Commit message
         CONFIG_ARM_COMPATIBLE_SEMIHOSTING and routing trap0 to the
         semihosting handler.
     
    -    Signed-off-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
    +    Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
         Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
    +    Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
    +
    + ## docs/system/target-hexagon.rst ##
    +@@ docs/system/target-hexagon.rst: Semihosting
    + -----------
    + Hexagon supports a semihosting interface similar to other architectures'.
    + The ``trap0`` instruction can activate these semihosting calls so that the
    +-guest software can access the host console and filesystem.  Semihosting
    +-is not yet implemented in QEMU hexagon.
    +-
    ++guest software can access the host console and filesystem. Read the
    ++`Hexagon Semihosting Specification
    ++<https://docs.qualcomm.com/doc/80-N2040-101_102648/topic/semihosting-specification.html>`__
    ++for details. Semihosting is enabled on qemu-system-hexagon machines by default,
    ++and it can be configured through ``-semihosting-config``.
    + 
    + Hexagon Features
    + ================
     
      ## configs/targets/hexagon-softmmu.mak ##
     @@ configs/targets/hexagon-softmmu.mak: TARGET_LONG_BITS=32
    @@ target/hexagon/hexswi.c
     +
     +    hexagon_read_memory(env, swi_info + 4, 4, &addr, retaddr);
     +    hexagon_read_memory(env, swi_info + 8, 4, &count, retaddr);
    -+    hexagon_touch_memory(env, addr, count, retaddr);
    ++    hexagon_peek_memory_range(env, addr, count, retaddr);
     +}
     +
     +static void sim_handle_trap0(CPUHexagonState *env)
     +{
     +    target_ulong what_swi, swi_info;
    -+    G_GNUC_UNUSED uintptr_t retaddr = 0;
     +    CPUState *cs = env_cpu(env);
     +
     +    g_assert(bql_locked());
    @@ target/hexagon/hexswi.c
     +    switch (what_swi) {
     +
     +    case HEX_SYS_EXCEPTION:
    ++    {
    ++        uint32_t ret = arch_get_thread_reg(env, HEX_REG_R02);
     +        arch_set_system_reg(env, HEX_SREG_MODECTL, 0);
    -+        qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
    -+        break;
    ++        gdb_exit(ret);
    ++        exit(ret);
    ++    }
    ++    break;
     +
     +    /* TODO: implement other hexagon-specific semihosting calls */
     +
 8:  8f1099dc944 !  9:  7399327e99b semihosting: add ftruncate helper (to be used for hexagon)
    @@ Commit message
         operation.  Add semihost_sys_ftruncate() so that Hexagon
         can delegate to it rather than calling ftruncate directly.
     
    -    Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
         Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
    +    Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
    +    Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
     
      ## include/semihosting/syscalls.h ##
     @@ include/semihosting/syscalls.h: void semihost_sys_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete,
 9:  45fc870a747 ! 10:  b66476c599c target/hexagon: add main arch-specific semihosting operations
    @@ Commit message
         that baremetal programs using the standard Hexagon simulator ABI can
         perform file I/O when running on qemu-system-hexagon.
     
    -    Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
         Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
    +    Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
     
      ## include/semihosting/common-semi.h ##
     @@
    @@ semihosting/arm-compat-semi.c: static inline uint32_t get_swi_errno(CPUState *cs
      #ifdef CONFIG_USER_ONLY
     
      ## target/hexagon/hexswi.c ##
    +@@ target/hexagon/hexswi.c: static inline bool is_hexagon_specific_swi_flag(enum hex_swi_flag what_swi)
    + }
    + #undef DEF_SWI_FLAG
    + 
    ++static const unsigned int angel_to_host_filemode_table[] = {
    ++    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_APPEND | O_CREAT,
    ++    O_WRONLY | O_APPEND | O_CREAT | O_BINARY,
    ++    O_RDWR | O_APPEND | O_CREAT,
    ++    O_RDWR | O_APPEND | O_CREAT | O_BINARY,
    ++    O_RDWR | O_CREAT,
    ++    O_RDWR | O_CREAT | O_EXCL
    ++};
    ++
    ++/*
    ++ * This must match the caller's definition, it would be in the
    ++ * caller's angel.h or equivalent header.
    ++ */
    ++struct __SYS_STAT {
    ++    uint64_t dev;
    ++    uint64_t ino;
    ++    uint32_t mode;
    ++    uint32_t nlink;
    ++    uint64_t rdev;
    ++    uint32_t size;
    ++    uint32_t __pad1;
    ++    uint32_t atime;
    ++    uint32_t mtime;
    ++    uint32_t ctime;
    ++    uint32_t __pad2;
    ++} sys_stat;
    ++
    + static void init_semihosting_guestfds(void)
    + {
    +     static gsize initialized;
     @@ target/hexagon/hexswi.c: static void do_preload(CPUHexagonState *env, target_ulong swi_info, bool load)
    -     hexagon_touch_memory(env, addr, count, retaddr);
    +     hexagon_peek_memory_range(env, addr, count, retaddr);
      }
      
     +static void common_semi_ftell_cb(CPUState *cs, uint64_t ret, int err)
    @@ target/hexagon/hexswi.c: static void do_preload(CPUHexagonState *env, target_ulo
      static void sim_handle_trap0(CPUHexagonState *env)
      {
          target_ulong what_swi, swi_info;
    +     CPUState *cs = env_cpu(env);
    ++    uintptr_t retaddr = 0;
    + 
    +     g_assert(bql_locked());
    +     init_semihosting_guestfds();
     @@ target/hexagon/hexswi.c: static void sim_handle_trap0(CPUHexagonState *env)
    -         qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
    -         break;
    +     }
    +     break;
      
     -    /* TODO: implement other hexagon-specific semihosting calls */
    -+#ifndef _WIN32
     +    case HEX_SYS_OPEN:
     +    {
     +        char filename[BUFSIZ];
    -+        target_ulong physicalFilenameAddr;
    ++        target_ulong physical_filename_addr;
     +        unsigned int filemode;
     +        int length;
     +        int real_openmode;
     +        int ret, err = 0;
     +        int i = 0;
    -+        static const unsigned int mode_table[] = {
    -+            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_APPEND | O_CREAT,
    -+            O_WRONLY | O_APPEND | O_CREAT | O_BINARY,
    -+            O_RDWR | O_APPEND | O_CREAT,
    -+            O_RDWR | O_APPEND | O_CREAT | O_BINARY,
    -+            O_RDWR | O_CREAT,
    -+            O_RDWR | O_CREAT | O_EXCL
    -+        };
     +
    -+
    -+        hexagon_read_memory(env, swi_info, 4, &physicalFilenameAddr, retaddr);
    ++        hexagon_read_memory(env, swi_info, 4, &physical_filename_addr, retaddr);
     +        hexagon_read_memory(env, swi_info + 4, 4, &filemode, retaddr);
     +        hexagon_read_memory(env, swi_info + 8, 4, &length, retaddr);
     +
    @@ target/hexagon/hexswi.c: static void sim_handle_trap0(CPUHexagonState *env)
     +        }
     +
     +        do {
    -+            hexagon_read_memory(env, physicalFilenameAddr + i, 1, &filename[i],
    ++            hexagon_read_memory(env, physical_filename_addr + i, 1, &filename[i],
     +                                retaddr);
     +            i++;
     +        } while (filename[i - 1]);
     +
     +        /* convert ARM ANGEL filemode into host filemode */
    -+        if (filemode < 14) {
    -+            real_openmode = mode_table[filemode];
    ++        if (filemode < ARRAY_SIZE(angel_to_host_filemode_table)) {
    ++            real_openmode = angel_to_host_filemode_table[filemode];
     +        } else {
     +            qemu_log_mask(LOG_GUEST_ERROR,
     +                          "%s: invalid OPEN mode: %u\n",
    @@ target/hexagon/hexswi.c: static void sim_handle_trap0(CPUHexagonState *env)
     +
     +    /*
     +     * Hexagon's SYS_ISTTY is a bit different than arm's: we do not return -1
    -+     * on error, neither errno. So we override with out own implementation.
    ++     * on error, neither errno. So we override with our own implementation.
     +     */
     +    case HEX_SYS_ISTTY:
     +    {
    @@ target/hexagon/hexswi.c: static void sim_handle_trap0(CPUHexagonState *env)
     +    case HEX_SYS_STAT:
     +    case HEX_SYS_FSTAT:
     +    {
    -+        /*
    -+         * This must match the caller's definition, it would be in the
    -+         * caller's angel.h or equivalent header.
    -+         */
    -+        struct __SYS_STAT {
    -+            uint64_t dev;
    -+            uint64_t ino;
    -+            uint32_t mode;
    -+            uint32_t nlink;
    -+            uint64_t rdev;
    -+            uint32_t size;
    -+            uint32_t __pad1;
    -+            uint32_t atime;
    -+            uint32_t mtime;
    -+            uint32_t ctime;
    -+            uint32_t __pad2;
    -+        } sys_stat;
     +        struct stat st_buf;
     +        uint8_t *st_bufptr = (uint8_t *)&sys_stat;
     +        int rc, err = 0;
     +        char filename[BUFSIZ];
    -+        target_ulong physicalFilenameAddr;
    ++        target_ulong physical_filename_addr;
     +        target_ulong statBufferAddr;
    -+        hexagon_read_memory(env, swi_info, 4, &physicalFilenameAddr, retaddr);
    ++        hexagon_read_memory(env, swi_info, 4, &physical_filename_addr, retaddr);
     +
     +        if (what_swi == HEX_SYS_STAT) {
     +            int i = 0;
     +            do {
    -+                hexagon_read_memory(env, physicalFilenameAddr + i, 1,
    ++                hexagon_read_memory(env, physical_filename_addr + i, 1,
     +                                    &filename[i], retaddr);
     +                i++;
     +            } while ((i < BUFSIZ) && filename[i - 1]);
     +            rc = stat(filename, &st_buf);
     +            err = errno;
     +        } else {
    -+            int fd = physicalFilenameAddr;
    ++            int fd = physical_filename_addr;
     +            GuestFD *gf = get_guestfd(fd);
     +            if (!gf || gf->type != GuestFDHost) {
     +                qemu_log_mask(LOG_UNIMP,
    @@ target/hexagon/hexswi.c: static void sim_handle_trap0(CPUHexagonState *env)
     +            sys_stat.nlink = (uint32_t) st_buf.st_nlink;
     +            sys_stat.rdev  = st_buf.st_rdev;
     +            sys_stat.size  = (uint32_t) st_buf.st_size;
    ++#if defined(__linux__)
     +            sys_stat.atime = (uint32_t) st_buf.st_atim.tv_sec;
     +            sys_stat.mtime = (uint32_t) st_buf.st_mtim.tv_sec;
     +            sys_stat.ctime = (uint32_t) st_buf.st_ctim.tv_sec;
    ++#elif defined(_WIN32)
    ++            sys_stat.atime = st_buf.st_atime;
    ++            sys_stat.mtime = st_buf.st_mtime;
    ++            sys_stat.ctime = st_buf.st_ctime;
    ++#endif
     +        }
     +        hexagon_read_memory(env, swi_info + 4, 4, &statBufferAddr, retaddr);
     +
    @@ target/hexagon/hexswi.c: static void sim_handle_trap0(CPUHexagonState *env)
     +                      " is unimplemented in QEMU\n",
     +                      (uint32_t)what_swi);
     +        break;
    -+
    -+#endif /* ! _WIN32 */
      
          default:
              qemu_log_mask(LOG_GUEST_ERROR,
10:  a2e686ac0ba ! 11:  7fd1831acb4 target/hexagon: add COREDUMP semihosting operation
    @@
      ## Metadata ##
    -Author: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
    +Author: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
     
      ## Commit message ##
         target/hexagon: add COREDUMP semihosting operation
    @@ Commit message
         Implement the handler to decode the SSR cause field and
         print the full register file, matching hexagon-sim behavior.
     
    -    Signed-off-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
    +    Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
         Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
    +    Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
     
      ## target/hexagon/internal.h ##
     @@ target/hexagon/internal.h: int hexagon_hvx_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n);
11:  db95d3b7af7 <  -:  ----------- target/hexagon: add OPEN/READ/CLOSE_DIR semihosting operations
12:  60a8f2decf0 ! 12:  24731ad7a27 target/hexagon: Add an errno mapping
    @@ Commit message
         guest so that baremetal programs see the expected error codes.
     
         Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
    +    Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
         Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
     
      ## target/hexagon/hexswi.c ##
     @@ target/hexagon/hexswi.c: static void do_preload(CPUHexagonState *env, target_ulong swi_info, bool load)
    -     hexagon_touch_memory(env, addr, count, retaddr);
    +     hexagon_peek_memory_range(env, addr, count, retaddr);
      }
      
     +/* Hexagon semihosting errno values */
    @@ target/hexagon/hexswi.c: static void sim_handle_trap0(CPUHexagonState *env)
          }
          break;
      
    -@@ target/hexagon/hexswi.c: static void sim_handle_trap0(CPUHexagonState *env)
    -         } else {
    -             err = errno;
    -         }
    --        common_semi_cb(cs, rc, rc != 0 ? 0 : err);
    -+        semi_cb(cs, rc, rc != 0 ? 0 : err);
    -         break;
    -     }
    - 
    -@@ target/hexagon/hexswi.c: static void sim_handle_trap0(CPUHexagonState *env)
    -             }
    -             rc = guest_dir_entry;
    -         }
    --        common_semi_cb(cs, rc, err);
    -+        semi_cb(cs, rc, err);
    -         break;
    -     }
    - 
    -@@ target/hexagon/hexswi.c: static void sim_handle_trap0(CPUHexagonState *env)
    -         } else {
    -             err = EBADF;
    -         }
    --        common_semi_cb(cs, ret, ret == 0 ? 0 : err);
    -+        semi_cb(cs, ret, ret == 0 ? 0 : err);
    -         break;
    -     }
    - 
     @@ target/hexagon/hexswi.c: static void sim_handle_trap0(CPUHexagonState *env)
          case HEX_SYS_PROF_STATSRESET:
          case HEX_SYS_DUMP_PMU_STATS:
13:  c366abf8749 ! 13:  c16ea7a7e6c python/machine: support routing semihosting output to the test console
    @@ Commit message
         console.
     
         Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
    +    Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
         Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
     
      ## python/qemu/machine/machine.py ##
14:  da280da8fec ! 14:  87a6d2559c3 tests/functional: Add hexagon semihosting systests
    @@ Commit message
         tests/functional: Add hexagon semihosting systests
     
         Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
    +    Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
         Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
     
      ## tests/functional/hexagon/meson.build (new) ##
    @@ tests/functional/hexagon/test_systests.py (new)
     +#!/usr/bin/env python3
     +#
     +# Copyright(c) Qualcomm Innovation Center, Inc. All Rights Reserved.
    -+#
     +# SPDX-License-Identifier: GPL-2.0-or-later
     +
     +import os
    @@ tests/functional/hexagon/test_systests.py (new)
     +from qemu_test import QemuSystemTest, Asset, wait_for_console_pattern
     +
     +
    -+_TARBALL_BIN_PATH = os.path.join(
    ++_TARBALL_BIN_PATH = (
     +    "systests_standalone_package",
     +    "StandaloneSysTests_6.4.0.2_v68",
     +    "bin",
     +)
     +
    -+
     +class SysTestsStandaloneTests(QemuSystemTest):
     +    SYSTEST_TIMEOUT_SEC = 30
     +
     +    ASSET_TARBALL = Asset(
    -+        "https://github.com/qualcomm/qemu-hexagon-testing/releases/download/v0.2.9/systests_standalone.tar.gz",
    -+        "db961ea3fcc389b478b3d5c2f3bac60bec87e7f3d7efef5e58a9ae8ee78d0e40",
    ++        "https://github.com/qualcomm/qemu-hexagon-testing/releases/download/v0.2.11/systests_standalone.tar.gz",
    ++        "b5777aa65245de7710a7a08d717953c1362be7c8b60d9014c9fee8b17610ad1c",
     +    )
     +
     +    def setUp(self):
     +        super().setUp()
     +        self.archive_extract(self.ASSET_TARBALL)
    -+        self.bin_dir = os.path.join(self.workdir, _TARBALL_BIN_PATH)
    -+        self._orig_cwd = os.getcwd()
    -+        os.chdir(self.workdir)
    -+        self.addCleanup(os.chdir, self._orig_cwd)
    -+
    -+    def tearDown(self):
    -+        if hasattr(self, "_orig_cwd"):
    -+            os.chdir(self._orig_cwd)
    -+        super().tearDown()
     +
     +    def binary(self, name):
    -+        """Return the full path to binary *name* inside bin_dir."""
    -+        return os.path.join(self.bin_dir, name)
    ++        """Return the full path to binary *name* inside bin dir."""
    ++        path = self.scratch_file(*_TARBALL_BIN_PATH, name)
    ++        self.assertTrue(os.path.exists(path))
    ++        return path
     +
     +    def run_exit_zero(self, binary_name, *extra_args, machine="V66G_1024"):
     +        """Launch *binary_name* and assert it exits with code 0.
     +
    -+        :param binary_name: name of the binary inside bin_dir.
    ++        :param binary_name: name of the binary inside bin dir.
     +        :param extra_args: optional pairs of (flag, value) strings passed
     +            to set_vm_arg(), e.g. ('-append', 'myarg').
     +        :param machine: QEMU machine type (default "V66G_1024").
    @@ tests/functional/hexagon/test_systests.py (new)
     +                            machine="V66G_1024"):
     +        """Launch *binary_name* and wait for *pattern* on the semihosting console.
     +
    -+        :param binary_name: name of the binary inside bin_dir.
    ++        :param binary_name: name of the binary inside bin dir.
     +        :param pattern: string pattern to wait for via wait_for_console_pattern.
     +        :param extra_args: optional pairs of (flag, value) strings passed
     +            to set_vm_arg(), e.g. ('-append', 'myarg').
    @@ tests/functional/hexagon/test_systests.py (new)
     +
     +    def test_fopen(self):
     +        """fopen reads a file passed via --append and verifies its contents."""
    -+        with open(os.path.join(self.workdir, "dummy.so"), "w") as f:
    ++        import tempfile
    ++        # The fopen binary has a short cmdline buffer; use a short path.
    ++        dummy = os.path.join(tempfile.gettempdir(), "qemu_fopen_test.so")
    ++        with open(dummy, "w") as f:
     +            f.write("valid\n")
    -+        self.run_exit_zero("fopen", "-append", "dummy.so")
    ++        self.run_exit_zero("fopen", "-append", dummy)
     +
     +    def test_ftrunc(self):
     +        """ftrunc truncates _testfile_ftrunc from 6 bytes to 1 byte."""
    -+        ftrunc_path = os.path.join(self.workdir, "_testfile_ftrunc")
    ++        ftrunc_path = self.scratch_file("_testfile_ftrunc")
     +        with open(ftrunc_path, "w") as f:
     +            f.write("valid\n")
     +        # Sleep 1 s so mtime change is observable
     +        time.sleep(1)
    -+        self.run_exit_zero("ftrunc")
    -+        self.assertEqual(
    -+            os.path.getsize(ftrunc_path),
    -+            1,
    -+            "_testfile_ftrunc should be 1 byte after ftrunc",
    -+        )
    -+
    -+    def test_dirent(self):
    -+        """dirent lists a directory passed via --append; output must be
    -+        '. .. fileA fileB'."""
    -+        dirent_dir = os.path.join(self.workdir, "_dirent_testdir")
    -+        os.makedirs(dirent_dir, exist_ok=True)
    -+        open(os.path.join(dirent_dir, "fileA"), "w").close()
    -+        open(os.path.join(dirent_dir, "fileB"), "w").close()
    -+        self.run_console_pattern(
    -+            "dirent", ". .. fileA fileB", "-append", "_dirent_testdir"
    -+        )
    ++        self.run_exit_zero("ftrunc", "-append", ftrunc_path)
    ++        self.assertEqual(os.path.getsize(ftrunc_path), 1,
    ++                         "_testfile_ftrunc should be 1 byte after ftrunc")
     +
     +    def test_access(self):
     +        """access checks R_OK|W_OK on _testfile_access."""
    -+        with open(os.path.join(self.workdir, "_testfile_access"), "w") as f:
    ++        testfile = self.scratch_file("_testfile_access")
    ++        with open(testfile, "w") as f:
     +            f.write("valid\n")
    -+        self.run_exit_zero("access")
    ++        self.run_exit_zero("access", "-append", testfile)
     +
     +    def test_semihost(self):
    -+        semihost_dir = os.path.join(self.workdir, "_semihost_dir")
    -+        os.makedirs(semihost_dir, exist_ok=True)
    -+        open(os.path.join(semihost_dir, "fileA"), "w").close()
    -+        open(os.path.join(semihost_dir, "fileB"), "w").close()
     +        self.run_console_pattern("semihost", "PASS", "-append", "arg1", "arg2")
     +
     +if __name__ == "__main__":
-- 
2.37.2



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

* [PATCH v2 01/14] target/hexagon: fix improper assign of cause code to exception index
  2026-07-16 18:06 [PATCH v2 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
@ 2026-07-16 18:06 ` Matheus Tavares Bernardino
  2026-07-16 18:18   ` Pierrick Bouvier
  2026-07-16 18:06 ` [PATCH v2 02/14] target/hexagon: fix get_phys_addr_debug with in-page offset Matheus Tavares Bernardino
                   ` (12 subsequent siblings)
  13 siblings, 1 reply; 19+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-16 18:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: brian.cain, pierrick.bouvier, marco.liebel, philmd, ale, anjo

hexagon_get_tb_cpu_state() detects a misaligned PC and raises an
exception, but it passed HEX_CAUSE_PC_NOT_ALIGNED (a cause code) as the
event argument to hexagon_raise_exception_err(), whose second parameter
is the event index (it ends up in cs->exception_index). This causes an
infinite reboot loop when we reache a misaligned PC.

Similarly, gen_exception_decode_fail() is called with a cause code
(HEX_CAUSE_INVALID_PACKET) but unconditionally routes it through
gen_exception(), which treats its argument as an event index and stores
it directly in cs->exception_index.

Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
---
 target/hexagon/cpu.c       | 3 ++-
 target/hexagon/translate.c | 4 ++++
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index 42d93e5da47..eac355497d8 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -320,7 +320,8 @@ static TCGTBCPUState hexagon_get_tb_cpu_state(CPUState *cs)
         hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, IS_TIGHT_LOOP, 1);
     }
     if (pc & PCALIGN_MASK) {
-        hexagon_raise_exception_err(env, HEX_CAUSE_PC_NOT_ALIGNED, 0);
+        env->cause_code = HEX_CAUSE_PC_NOT_ALIGNED;
+        hexagon_raise_exception_err(env, HEX_EVENT_PRECISE, (uint32_t)pc);
     }
 
 #ifndef CONFIG_USER_ONLY
diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
index 77235916f4b..341842c6af1 100644
--- a/target/hexagon/translate.c
+++ b/target/hexagon/translate.c
@@ -238,7 +238,11 @@ static void gen_exception_decode_fail(DisasContext *ctx, int nwords, int excp)
 
     gen_exec_counters(ctx);
     tcg_gen_movi_tl(hex_gpr[HEX_REG_PC], fail_pc);
+#ifdef CONFIG_USER_ONLY
     gen_exception(excp, fail_pc);
+#else
+    gen_precise_exception(excp, fail_pc);
+#endif
     ctx->base.is_jmp = DISAS_NORETURN;
     ctx->base.pc_next = fail_pc;
 }
-- 
2.37.2



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

* [PATCH v2 02/14] target/hexagon: fix get_phys_addr_debug with in-page offset
  2026-07-16 18:06 [PATCH v2 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
  2026-07-16 18:06 ` [PATCH v2 01/14] target/hexagon: fix improper assign of cause code to exception index Matheus Tavares Bernardino
@ 2026-07-16 18:06 ` Matheus Tavares Bernardino
  2026-07-16 18:06 ` [PATCH v2 03/14] target/hexagon: fix PC advancement for non-COF TB terminators Matheus Tavares Bernardino
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-16 18:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: brian.cain, pierrick.bouvier, marco.liebel, philmd, ale, anjo

As documented:

     * @get_phys_addr_debug: Callback for obtaining a physical address.
     * This must be able to handle a non-page-aligned address, and will
     * return the physical address corresponding to that address.

When MMU is enabled, hexagon_cpu_get_phys_addr_debug() returns the
physical address page-aligned, not corrected to reflect the exact byte
the virtual addr maps to within the page. Let's fix that. The
MMU-disabled case is already correct.

This would break semihosting argument reads when it is added for Hexagon.

Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
---
 target/hexagon/cpu.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index eac355497d8..73a799da877 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -570,7 +570,9 @@ static hwaddr hexagon_cpu_get_phys_addr_debug(CPUState *cs, vaddr addr)
 
     if (get_physical_address(env, &phys_addr, &prot, &page_size, &excp,
                              addr, 0, mmu_idx)) {
+        vaddr page_offset = addr & (TARGET_PAGE_SIZE - 1);
         find_qemu_subpage(&addr, &phys_addr, page_size);
+        phys_addr += hexagon_cpu_mmu_enabled(env) ? page_offset : 0;
         return phys_addr;
     }
 
-- 
2.37.2



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

* [PATCH v2 03/14] target/hexagon: fix PC advancement for non-COF TB terminators
  2026-07-16 18:06 [PATCH v2 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
  2026-07-16 18:06 ` [PATCH v2 01/14] target/hexagon: fix improper assign of cause code to exception index Matheus Tavares Bernardino
  2026-07-16 18:06 ` [PATCH v2 02/14] target/hexagon: fix get_phys_addr_debug with in-page offset Matheus Tavares Bernardino
@ 2026-07-16 18:06 ` Matheus Tavares Bernardino
  2026-07-16 18:06 ` [PATCH v2 04/14] target/hexagon: add aux functions for guest mem load/store Matheus Tavares Bernardino
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-16 18:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: brian.cain, pierrick.bouvier, marco.liebel, philmd, ale, anjo

Some packets end a translation block without a change-of-flow. These do
not update the PC during commit, so gen_end_tb() leaves
hex_gpr[HEX_REG_PC] pointing at the same packet and the block gets
re-entered forever. Set PC explicitly to next_PC in that gen_end_tb()
branch to fix execution of next blocks.

Note that gen_start_packet() used to have a special case for
tlblock/k0lock, setting ctx->next_PC to the packet's own address. This
relies on the tlblock/k0lock helpers to properly advance the PC, which
is never done (only env->next_PC is updated, but that never reaches
hex_gpr[HEX_REG_PC]).  Drop the special case so these packets advance to
the following packet like any other non-COF TB terminator.

Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
---
 target/hexagon/translate.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
index 341842c6af1..f8b87c279e5 100644
--- a/target/hexagon/translate.c
+++ b/target/hexagon/translate.c
@@ -210,6 +210,12 @@ static void gen_end_tb(DisasContext *ctx)
         gen_goto_tb(ctx, 0, ctx->base.tb->pc, true);
         gen_set_label(skip);
         gen_goto_tb(ctx, 1, ctx->next_PC, false);
+    } else if (!ctx->pkt.pkt_has_cof) {
+        /*
+         * Packet with no deferred COF that still ends the TB. PC is
+         * not updated during commit, so set it explicitly to next_PC.
+         */
+         gen_goto_tb(ctx, 0, ctx->next_PC, true);
     } else {
         tcg_gen_lookup_and_goto_ptr();
     }
@@ -286,6 +292,7 @@ static bool check_for_attrib(Packet *pkt, int attrib)
     return false;
 }
 
+#ifndef CONFIG_USER_ONLY
 static bool check_for_opcode(Packet *pkt, uint16_t opcode)
 {
     for (int i = 0; i < pkt->num_insns; i++) {
@@ -295,6 +302,7 @@ static bool check_for_opcode(Packet *pkt, uint16_t opcode)
     }
     return false;
 }
+#endif
 
 static bool need_slot_cancelled(Packet *pkt)
 {
@@ -566,10 +574,7 @@ static void analyze_packet(DisasContext *ctx)
 static void gen_start_packet(DisasContext *ctx)
 {
     Packet *pkt = &ctx->pkt;
-    target_ulong next_PC = (check_for_opcode(pkt, Y2_k0lock) ||
-                            check_for_opcode(pkt, Y2_tlblock)) ?
-                               ctx->base.pc_next :
-                               ctx->base.pc_next + pkt->encod_pkt_size_in_bytes;
+    target_ulong next_PC = ctx->base.pc_next + pkt->encod_pkt_size_in_bytes;
     int i;
 
     /* Clear out the disassembly context */
-- 
2.37.2



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

* [PATCH v2 04/14] target/hexagon: add aux functions for guest mem load/store
  2026-07-16 18:06 [PATCH v2 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
                   ` (2 preceding siblings ...)
  2026-07-16 18:06 ` [PATCH v2 03/14] target/hexagon: fix PC advancement for non-COF TB terminators Matheus Tavares Bernardino
@ 2026-07-16 18:06 ` Matheus Tavares Bernardino
  2026-07-16 18:06 ` [PATCH v2 05/14] hexagon: cpu_helper: add reg reading/writing helpers Matheus Tavares Bernardino
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-16 18:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: brian.cain, pierrick.bouvier, marco.liebel, philmd, ale, anjo

Will be used for semihosting.

Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
---
 target/hexagon/cpu_helper.h |   6 ++
 target/hexagon/cpu_helper.c | 133 ++++++++++++++++++++++++++++++++++++
 2 files changed, 139 insertions(+)

diff --git a/target/hexagon/cpu_helper.h b/target/hexagon/cpu_helper.h
index d1767503156..ca2e13ab1d1 100644
--- a/target/hexagon/cpu_helper.h
+++ b/target/hexagon/cpu_helper.h
@@ -7,6 +7,12 @@
 #ifndef HEXAGON_CPU_HELPER_H
 #define HEXAGON_CPU_HELPER_H
 
+void hexagon_read_memory(CPUHexagonState *env, target_ulong vaddr, int size,
+                         void *retptr, uintptr_t retaddr);
+void hexagon_write_memory(CPUHexagonState *env, target_ulong vaddr,
+                          int size, uint64_t data, uintptr_t retaddr);
+void hexagon_peek_memory_range(CPUHexagonState *env, uint32_t start_addr,
+                               uint32_t length, uintptr_t retaddr);
 uint32_t hexagon_get_pmu_counter(CPUHexagonState *cur_env, int index);
 void hexagon_modify_ssr(CPUHexagonState *env, uint32_t new, uint32_t old);
 int get_cpu_mode(CPUHexagonState *env);
diff --git a/target/hexagon/cpu_helper.c b/target/hexagon/cpu_helper.c
index 64c5746c6d9..e981e11a35d 100644
--- a/target/hexagon/cpu_helper.c
+++ b/target/hexagon/cpu_helper.c
@@ -25,6 +25,139 @@
 #include "sys_macros.h"
 #include "arch.h"
 
+#ifndef CONFIG_USER_ONLY
+
+static bool hexagon_read_memory_small(CPUHexagonState *env, target_ulong addr,
+                                      int byte_count, unsigned char *dstbuf,
+                                      int mmu_idx, uintptr_t retaddr)
+ {
+    /* handle small sizes */
+    switch (byte_count) {
+    case 1:
+        *dstbuf = cpu_ldub_mmuidx_ra(env, addr, mmu_idx, retaddr);
+        return true;
+
+    case 2:
+        if (QEMU_IS_ALIGNED(addr, 2)) {
+            *(unsigned short *)dstbuf =
+                cpu_lduw_le_mmuidx_ra(env, addr, mmu_idx, retaddr);
+            return true;
+        }
+        break;
+
+    case 4:
+        if (QEMU_IS_ALIGNED(addr, 4)) {
+            *(uint32_t *)dstbuf =
+                cpu_ldl_le_mmuidx_ra(env, addr, mmu_idx, retaddr);
+            return true;
+        }
+        break;
+
+    case 8:
+        if (QEMU_IS_ALIGNED(addr, 8)) {
+            *(uint64_t *)dstbuf =
+                cpu_ldq_le_mmuidx_ra(env, addr, mmu_idx, retaddr);
+            return true;
+        }
+        break;
+
+    default:
+        /* larger request, handle elsewhere */
+        return false;
+    }
+
+    /* not aligned, copy bytes */
+    for (int i = 0; i < byte_count; ++i) {
+        *dstbuf++ = cpu_ldub_mmuidx_ra(env, addr++, mmu_idx, retaddr);
+    }
+    return true;
+}
+
+void hexagon_read_memory(CPUHexagonState *env, target_ulong vaddr, int size,
+                         void *retptr, uintptr_t retaddr)
+{
+    BQL_LOCK_GUARD();
+    CPUState *cs = env_cpu(env);
+    unsigned mmu_idx = cpu_mmu_index(cs, false);
+    if (!hexagon_read_memory_small(env, vaddr, size, retptr, mmu_idx,
+                                   retaddr)) {
+        cpu_abort(cs, "%s: ERROR: bad size = %d!\n", __func__, size);
+    }
+}
+
+static bool hexagon_write_memory_small(CPUHexagonState *env, target_ulong addr,
+                                       int byte_count, unsigned char *srcbuf,
+                                       int mmu_idx, uintptr_t retaddr)
+{
+    /* handle small sizes */
+    switch (byte_count) {
+    case 1:
+        cpu_stb_mmuidx_ra(env, addr, *srcbuf, mmu_idx, retaddr);
+        return true;
+
+    case 2:
+        if (QEMU_IS_ALIGNED(addr, 2)) {
+            cpu_stw_le_mmuidx_ra(env, addr, *(uint16_t *)srcbuf, mmu_idx, retaddr);
+            return true;
+        }
+        break;
+
+    case 4:
+        if (QEMU_IS_ALIGNED(addr, 4)) {
+            cpu_stl_le_mmuidx_ra(env, addr, *(uint32_t *)srcbuf, mmu_idx, retaddr);
+            return true;
+        }
+        break;
+
+    case 8:
+        if (QEMU_IS_ALIGNED(addr, 8)) {
+            cpu_stq_le_mmuidx_ra(env, addr, *(uint64_t *)srcbuf, mmu_idx, retaddr);
+            return true;
+        }
+        break;
+
+    default:
+        /* larger request, handle elsewhere */
+        return false;
+    }
+
+    /* not aligned, copy bytes */
+    for (int i = 0; i < byte_count; ++i) {
+        cpu_stb_mmuidx_ra(env, addr++, *srcbuf++, mmu_idx, retaddr);
+    }
+
+    return true;
+}
+
+void hexagon_write_memory(CPUHexagonState *env, target_ulong vaddr,
+                          int size, uint64_t data, uintptr_t retaddr)
+{
+    CPUState *cs = env_cpu(env);
+    unsigned mmu_idx = cpu_mmu_index(cs, false);
+    if (!hexagon_write_memory_small(env, vaddr, size, (unsigned char *)&data,
+                                   mmu_idx, retaddr)) {
+        cpu_abort(cs, "%s: ERROR: bad size = %d!\n", __func__, size);
+    }
+}
+
+static inline uint32_t page_start(uint32_t addr)
+{
+    uint32_t page_align = ~(TARGET_PAGE_SIZE - 1);
+    return addr & page_align;
+}
+
+void hexagon_peek_memory_range(CPUHexagonState *env, uint32_t start_addr,
+                               uint32_t length, uintptr_t retaddr)
+{
+    unsigned int warm;
+    uint32_t first = page_start(start_addr);
+    uint32_t last = page_start(start_addr + length - 1);
+    for (uint32_t page = first; page <= last; page += TARGET_PAGE_SIZE) {
+        hexagon_read_memory(env, page, 1, &warm, retaddr);
+    }
+}
+
+#endif
 
 uint32_t hexagon_get_pmu_counter(CPUHexagonState *cur_env, int index)
 {
-- 
2.37.2



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

* [PATCH v2 05/14] hexagon: cpu_helper: add reg reading/writing helpers
  2026-07-16 18:06 [PATCH v2 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
                   ` (3 preceding siblings ...)
  2026-07-16 18:06 ` [PATCH v2 04/14] target/hexagon: add aux functions for guest mem load/store Matheus Tavares Bernardino
@ 2026-07-16 18:06 ` Matheus Tavares Bernardino
  2026-07-16 18:06 ` [PATCH v2 06/14] semihosting: add APIs for chardev-aware guest fd routing Matheus Tavares Bernardino
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-16 18:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: brian.cain, pierrick.bouvier, marco.liebel, philmd, ale, anjo

And adjust op_helper to use those. They will also be used on upcoming
semihosting commits.

Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
---
 target/hexagon/cpu_helper.h | 18 +++++++++++++++++
 target/hexagon/cpu_helper.c | 40 +++++++++++++++++++++++++++++++++++++
 target/hexagon/op_helper.c  | 18 ++---------------
 3 files changed, 60 insertions(+), 16 deletions(-)

diff --git a/target/hexagon/cpu_helper.h b/target/hexagon/cpu_helper.h
index ca2e13ab1d1..757a49fc4d4 100644
--- a/target/hexagon/cpu_helper.h
+++ b/target/hexagon/cpu_helper.h
@@ -7,6 +7,24 @@
 #ifndef HEXAGON_CPU_HELPER_H
 #define HEXAGON_CPU_HELPER_H
 
+static inline void arch_set_thread_reg(CPUHexagonState *env, uint32_t reg,
+                                       uint32_t val)
+{
+    g_assert(reg < TOTAL_PER_THREAD_REGS);
+    env->gpr[reg] = val;
+}
+
+static inline uint32_t arch_get_thread_reg(CPUHexagonState *env, uint32_t reg)
+{
+    g_assert(reg < TOTAL_PER_THREAD_REGS);
+    return env->gpr[reg];
+}
+
+void arch_set_system_reg(CPUHexagonState *env, uint32_t reg, uint32_t val);
+void arch_set_system_reg_masked(CPUHexagonState *env, uint32_t reg,
+                                uint32_t val);
+uint32_t arch_get_system_reg(CPUHexagonState *env, uint32_t reg);
+
 void hexagon_read_memory(CPUHexagonState *env, target_ulong vaddr, int size,
                          void *retptr, uintptr_t retaddr);
 void hexagon_write_memory(CPUHexagonState *env, target_ulong vaddr,
diff --git a/target/hexagon/cpu_helper.c b/target/hexagon/cpu_helper.c
index e981e11a35d..98ce599571e 100644
--- a/target/hexagon/cpu_helper.c
+++ b/target/hexagon/cpu_helper.c
@@ -27,6 +27,46 @@
 
 #ifndef CONFIG_USER_ONLY
 
+uint32_t arch_get_system_reg(CPUHexagonState *env, uint32_t reg)
+{
+    if (reg == HEX_SREG_PCYCLELO) {
+        return hexagon_get_sys_pcycle_count_low(env);
+    } else if (reg == HEX_SREG_PCYCLEHI) {
+        return hexagon_get_sys_pcycle_count_high(env);
+    }
+
+    g_assert(reg < NUM_SREGS);
+    if (reg < HEX_SREG_GLB_START) {
+        return env->t_sreg[reg];
+    } else {
+        HexagonCPU *cpu = env_archcpu(env);
+        return hexagon_globalreg_read(cpu->globalregs, reg, env->threadId);
+    }
+}
+
+void arch_set_system_reg(CPUHexagonState *env, uint32_t reg, uint32_t val)
+{
+    g_assert(reg < NUM_SREGS);
+    if (reg < HEX_SREG_GLB_START) {
+        env->t_sreg[reg] = val;
+    } else {
+        HexagonCPU *cpu = env_archcpu(env);
+        hexagon_globalreg_write(cpu->globalregs, reg, val, env->threadId);
+    }
+}
+
+void arch_set_system_reg_masked(CPUHexagonState *env, uint32_t reg,
+                                uint32_t val)
+{
+    g_assert(reg < NUM_SREGS);
+    if (reg < HEX_SREG_GLB_START) {
+        env->t_sreg[reg] = val;
+    } else {
+        HexagonCPU *cpu = env_archcpu(env);
+        hexagon_globalreg_write_masked(cpu->globalregs, reg, val);
+    }
+}
+
 static bool hexagon_read_memory_small(CPUHexagonState *env, target_ulong addr,
                                       int byte_count, unsigned char *dstbuf,
                                       int mmu_idx, uintptr_t retaddr)
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index 125952aee59..4859d8a484e 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -1839,28 +1839,14 @@ void HELPER(setimask)(CPUHexagonState *env, uint32_t tid, uint32_t imask)
 void HELPER(sreg_write_masked)(CPUHexagonState *env, uint32_t reg, uint32_t val)
 {
     BQL_LOCK_GUARD();
-    if (reg < HEX_SREG_GLB_START) {
-        env->t_sreg[reg] = val;
-    } else {
-        HexagonCPU *cpu = env_archcpu(env);
-        if (cpu->globalregs) {
-            hexagon_globalreg_write_masked(cpu->globalregs, reg, val);
-        }
-    }
+    arch_set_system_reg_masked(env, reg, val);
 }
 
 static inline QEMU_ALWAYS_INLINE uint32_t sreg_read(CPUHexagonState *env,
                                                     uint32_t reg)
 {
-    HexagonCPU *cpu;
-
     g_assert(bql_locked());
-    if (reg < HEX_SREG_GLB_START) {
-        return env->t_sreg[reg];
-    }
-    cpu = env_archcpu(env);
-    return cpu->globalregs ?
-        hexagon_globalreg_read(cpu->globalregs, reg, env->threadId) : 0;
+    return arch_get_system_reg(env, reg);
 }
 
 uint32_t HELPER(sreg_read)(CPUHexagonState *env, uint32_t reg)
-- 
2.37.2



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

* [PATCH v2 06/14] semihosting: add APIs for chardev-aware guest fd routing
  2026-07-16 18:06 [PATCH v2 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
                   ` (4 preceding siblings ...)
  2026-07-16 18:06 ` [PATCH v2 05/14] hexagon: cpu_helper: add reg reading/writing helpers Matheus Tavares Bernardino
@ 2026-07-16 18:06 ` Matheus Tavares Bernardino
  2026-07-16 18:06 ` [PATCH v2 07/14] semihosting: add callback to set error Matheus Tavares Bernardino
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-16 18:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: brian.cain, pierrick.bouvier, marco.liebel, philmd, ale, anjo,
	Alex Bennée

From: Brian Cain <brian.cain@oss.qualcomm.com>

Add qemu_semihosting_console_has_chardev() to query whether the
semihosting console is backed by a chardev, and console_guestfd()
to initialize a guest file descriptor as GuestFDConsole.

These APIs enable callers to route semihosting I/O through a chardev
rather than directly to host stdio.

Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
---
 include/semihosting/console.h | 9 +++++++++
 include/semihosting/guestfd.h | 9 +++++++++
 semihosting/console.c         | 5 +++++
 semihosting/guestfd.c         | 8 ++++++++
 4 files changed, 31 insertions(+)

diff --git a/include/semihosting/console.h b/include/semihosting/console.h
index 1c12e178ee3..d5f149e2088 100644
--- a/include/semihosting/console.h
+++ b/include/semihosting/console.h
@@ -54,4 +54,13 @@ void qemu_semihosting_console_block_until_ready(CPUState *cs);
  */
 bool qemu_semihosting_console_ready(void);
 
+/**
+ * qemu_semihosting_console_has_chardev:
+ *
+ * Return true if the semihosting console is backed by a chardev.
+ * When true, console I/O goes through the chardev rather than
+ * host stdio.
+ */
+bool qemu_semihosting_console_has_chardev(void);
+
 #endif /* SEMIHOST_CONSOLE_H */
diff --git a/include/semihosting/guestfd.h b/include/semihosting/guestfd.h
index a7ea1041ea0..76ca0fcf1a7 100644
--- a/include/semihosting/guestfd.h
+++ b/include/semihosting/guestfd.h
@@ -70,6 +70,15 @@ GuestFD *get_guestfd(int guestfd);
  */
 void associate_guestfd(int guestfd, int hostfd);
 
+/**
+ * console_guestfd:
+ * @guestfd: GuestFD index
+ *
+ * Initialize the GuestFD for @guestfd to GuestFDConsole.
+ * I/O will be routed through the semihosting console chardev.
+ */
+void console_guestfd(int guestfd);
+
 /**
  * staticfile_guestfd:
  * @guestfd: GuestFD index
diff --git a/semihosting/console.c b/semihosting/console.c
index 91e5d50d502..9d786833564 100644
--- a/semihosting/console.c
+++ b/semihosting/console.c
@@ -108,6 +108,11 @@ int qemu_semihosting_console_read(CPUState *cs, void *buf, int len)
     return ret;
 }
 
+bool qemu_semihosting_console_has_chardev(void)
+{
+    return console.chr != NULL;
+}
+
 int qemu_semihosting_console_write(void *buf, int len)
 {
     if (console.chr) {
diff --git a/semihosting/guestfd.c b/semihosting/guestfd.c
index e8f236c690c..8b5770bab0d 100644
--- a/semihosting/guestfd.c
+++ b/semihosting/guestfd.c
@@ -117,6 +117,14 @@ void associate_guestfd(int guestfd, int hostfd)
     gf->hostfd = hostfd;
 }
 
+void console_guestfd(int guestfd)
+{
+    GuestFD *gf = do_get_guestfd(guestfd);
+
+    assert(gf);
+    gf->type = GuestFDConsole;
+}
+
 void staticfile_guestfd(int guestfd, const uint8_t *data, size_t len)
 {
     GuestFD *gf = do_get_guestfd(guestfd);
-- 
2.37.2



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

* [PATCH v2 07/14] semihosting: add callback to set error
  2026-07-16 18:06 [PATCH v2 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
                   ` (5 preceding siblings ...)
  2026-07-16 18:06 ` [PATCH v2 06/14] semihosting: add APIs for chardev-aware guest fd routing Matheus Tavares Bernardino
@ 2026-07-16 18:06 ` Matheus Tavares Bernardino
  2026-07-16 18:06 ` [PATCH v2 08/14] target/hexagon: add semihosting support Matheus Tavares Bernardino
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-16 18:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: brian.cain, pierrick.bouvier, marco.liebel, philmd, ale, anjo,
	Daniel Henrique Barboza, Alex Bennée, Peter Maydell,
	Palmer Dabbelt, Alistair Francis, Weiwei Li, Liu Zhiwei, Chao Liu,
	qemu-arm, qemu-riscv

This is currently unused by existing semihosting targets, but it will be
used by hexagon in the following commit.

Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
---
 include/semihosting/common-semi.h | 1 +
 semihosting/arm-compat-semi.c     | 1 +
 target/arm/common-semi-target.c   | 4 ++++
 target/riscv/common-semi-target.c | 4 ++++
 4 files changed, 10 insertions(+)

diff --git a/include/semihosting/common-semi.h b/include/semihosting/common-semi.h
index aa511a46f42..a11905ef4ef 100644
--- a/include/semihosting/common-semi.h
+++ b/include/semihosting/common-semi.h
@@ -37,6 +37,7 @@
 void do_common_semihosting(CPUState *cs);
 uint64_t common_semi_arg(CPUState *cs, int argno);
 void common_semi_set_ret(CPUState *cs, uint64_t ret);
+void common_semi_set_err(CPUState *cs, int err);
 bool is_64bit_semihosting(CPUArchState *env);
 bool common_semi_sys_exit_is_extended(CPUState *cs);
 uint64_t common_semi_stack_bottom(CPUState *cs);
diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index 5e5f181b908..c54753f696f 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -237,6 +237,7 @@ static void common_semi_cb(CPUState *cs, uint64_t ret, int err)
         ts->swi_errno = err;
 #else
         syscall_err = err;
+        common_semi_set_err(cs, err);
 #endif
     }
     common_semi_set_ret(cs, ret);
diff --git a/target/arm/common-semi-target.c b/target/arm/common-semi-target.c
index 2b77ce9c17b..38d52deb3d6 100644
--- a/target/arm/common-semi-target.c
+++ b/target/arm/common-semi-target.c
@@ -34,6 +34,10 @@ void common_semi_set_ret(CPUState *cs, uint64_t ret)
     }
 }
 
+void common_semi_set_err(CPUState *cs, int err)
+{
+}
+
 bool common_semi_sys_exit_is_extended(CPUState *cs)
 {
     return is_a64(cpu_env(cs));
diff --git a/target/riscv/common-semi-target.c b/target/riscv/common-semi-target.c
index aeaeb88d536..38a00e160c3 100644
--- a/target/riscv/common-semi-target.c
+++ b/target/riscv/common-semi-target.c
@@ -26,6 +26,10 @@ void common_semi_set_ret(CPUState *cs, uint64_t ret)
     env->gpr[xA0] = ret;
 }
 
+void common_semi_set_err(CPUState *cs, int err)
+{
+}
+
 bool is_64bit_semihosting(CPUArchState *env)
 {
     return riscv_cpu_mxl(env) != MXL_RV32;
-- 
2.37.2



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

* [PATCH v2 08/14] target/hexagon: add semihosting support
  2026-07-16 18:06 [PATCH v2 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
                   ` (6 preceding siblings ...)
  2026-07-16 18:06 ` [PATCH v2 07/14] semihosting: add callback to set error Matheus Tavares Bernardino
@ 2026-07-16 18:06 ` Matheus Tavares Bernardino
  2026-07-16 21:08   ` Brian Cain
  2026-07-16 18:06 ` [PATCH v2 09/14] semihosting: add ftruncate helper (to be used for hexagon) Matheus Tavares Bernardino
                   ` (5 subsequent siblings)
  13 siblings, 1 reply; 19+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-16 18:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: brian.cain, pierrick.bouvier, marco.liebel, philmd, ale, anjo,
	Paolo Bonzini

Baremetal Hexagon programs use trap0 #0 to invoke
semihosting calls for I/O and process control.  Wire up the
arm-compatible semihosting framework for softmmu by enabling
CONFIG_ARM_COMPATIBLE_SEMIHOSTING and routing trap0 to the
semihosting handler.

Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
---
 docs/system/target-hexagon.rst      |   8 +-
 configs/targets/hexagon-softmmu.mak |   2 +
 hw/hexagon/hexagon_dsp.c            |   2 +
 target/hexagon/common-semi-target.c |  51 +++++++++
 target/hexagon/hexswi.c             | 167 +++++++++++++++++++++++++++-
 hw/hexagon/Kconfig                  |   1 +
 qemu-options.hx                     |   8 +-
 target/hexagon/meson.build          |   3 +
 8 files changed, 232 insertions(+), 10 deletions(-)
 create mode 100644 target/hexagon/common-semi-target.c

diff --git a/docs/system/target-hexagon.rst b/docs/system/target-hexagon.rst
index 416b8f7be76..36115137626 100644
--- a/docs/system/target-hexagon.rst
+++ b/docs/system/target-hexagon.rst
@@ -91,9 +91,11 @@ Semihosting
 -----------
 Hexagon supports a semihosting interface similar to other architectures'.
 The ``trap0`` instruction can activate these semihosting calls so that the
-guest software can access the host console and filesystem.  Semihosting
-is not yet implemented in QEMU hexagon.
-
+guest software can access the host console and filesystem. Read the
+`Hexagon Semihosting Specification
+<https://docs.qualcomm.com/doc/80-N2040-101_102648/topic/semihosting-specification.html>`__
+for details. Semihosting is enabled on qemu-system-hexagon machines by default,
+and it can be configured through ``-semihosting-config``.
 
 Hexagon Features
 ================
diff --git a/configs/targets/hexagon-softmmu.mak b/configs/targets/hexagon-softmmu.mak
index a77c100f0c5..6cbdc64be56 100644
--- a/configs/targets/hexagon-softmmu.mak
+++ b/configs/targets/hexagon-softmmu.mak
@@ -6,3 +6,5 @@ TARGET_LONG_BITS=32
 TARGET_NOT_USING_LEGACY_LDST_PHYS_API=y
 TARGET_NOT_USING_LEGACY_NATIVE_ENDIAN_API=y
 TARGET_NEED_FDT=y
+CONFIG_SEMIHOSTING=y
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
diff --git a/hw/hexagon/hexagon_dsp.c b/hw/hexagon/hexagon_dsp.c
index aa493993229..315733cded3 100644
--- a/hw/hexagon/hexagon_dsp.c
+++ b/hw/hexagon/hexagon_dsp.c
@@ -27,6 +27,7 @@
 #include "target/hexagon/internal.h"
 #include "system/physmem.h"
 #include "system/reset.h"
+#include "semihosting/semihost.h"
 
 #include "machine_cfg_v66g_1024.h.inc"
 
@@ -178,6 +179,7 @@ static void init_mc(MachineClass *mc)
     mc->no_serial = 1;
     mc->is_default = false;
     mc->max_cpus = 8;
+    qemu_semihosting_enable();
 }
 
 /* ----------------------------------------------------------------- */
diff --git a/target/hexagon/common-semi-target.c b/target/hexagon/common-semi-target.c
new file mode 100644
index 00000000000..9a7720514bb
--- /dev/null
+++ b/target/hexagon/common-semi-target.c
@@ -0,0 +1,51 @@
+/*
+ * Target-specific parts of semihosting/arm-compat-semi.c.
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "cpu_helper.h"
+#include "semihosting/common-semi.h"
+
+uint64_t common_semi_arg(CPUState *cs, int argno)
+{
+    CPUHexagonState *env = cpu_env(cs);
+    return arch_get_thread_reg(env, HEX_REG_R00 + argno);
+}
+
+void common_semi_set_ret(CPUState *cs, uint64_t ret)
+{
+    CPUHexagonState *env = cpu_env(cs);
+    arch_set_thread_reg(env, HEX_REG_R00, ret);
+}
+
+void common_semi_set_err(CPUState *cs, int err)
+{
+    CPUHexagonState *env = cpu_env(cs);
+    arch_set_thread_reg(env, HEX_REG_R01, err);
+}
+
+bool common_semi_sys_exit_is_extended(CPUState *cs)
+{
+    return false;
+}
+
+bool is_64bit_semihosting(CPUArchState *env)
+{
+    return false;
+}
+
+uint64_t common_semi_stack_bottom(CPUState *cs)
+{
+    CPUHexagonState *env = cpu_env(cs);
+    return arch_get_thread_reg(env, HEX_REG_SP);
+}
+
+bool common_semi_has_synccache(CPUArchState *env)
+{
+    return false;
+}
diff --git a/target/hexagon/hexswi.c b/target/hexagon/hexswi.c
index 43c373ea2ee..2aedd8368e2 100644
--- a/target/hexagon/hexswi.c
+++ b/target/hexagon/hexswi.c
@@ -24,9 +24,171 @@
 #error "This file is only used in system emulation"
 #endif
 
+#include "semihosting/common-semi.h"
+#include "semihosting/console.h"
+#include "semihosting/syscalls.h"
+#include "semihosting/guestfd.h"
+#include "system/runstate.h"
+
+/* non-arm-compatible semihosting calls */
+#define HEXAGON_SPECIFIC_SWI_FLAGS \
+    DEF_SWI_FLAG(OPEN,             0x01) \
+    DEF_SWI_FLAG(ISTTY,            0x09) \
+    DEF_SWI_FLAG(HEAPINFO,         0x16) \
+    DEF_SWI_FLAG(EXCEPTION,        0x18) \
+    DEF_SWI_FLAG(SEEK,             0x0A) \
+    DEF_SWI_FLAG(READ_CYCLES,      0x40) \
+    DEF_SWI_FLAG(PROF_ON,          0x41) \
+    DEF_SWI_FLAG(PROF_OFF,         0x42) \
+    DEF_SWI_FLAG(WRITECREG,        0x43) \
+    DEF_SWI_FLAG(READ_TCYCLES,     0x44) \
+    DEF_SWI_FLAG(LOG_EVENT,        0x45) \
+    DEF_SWI_FLAG(REDRAW,           0x46) \
+    DEF_SWI_FLAG(READ_ICOUNT,      0x47) \
+    DEF_SWI_FLAG(PROF_STATSRESET,  0x48) \
+    DEF_SWI_FLAG(DUMP_PMU_STATS,   0x4a) \
+    DEF_SWI_FLAG(READ_PCYCLES,     0x52) \
+    DEF_SWI_FLAG(COREDUMP,         0xCD) \
+    DEF_SWI_FLAG(FTELL,            0x100) \
+    DEF_SWI_FLAG(FSTAT,            0x101) \
+    DEF_SWI_FLAG(STAT,             0x103) \
+    DEF_SWI_FLAG(GETCWD,           0x104) \
+    DEF_SWI_FLAG(ACCESS,           0x105) \
+    DEF_SWI_FLAG(OPENDIR,          0x180) \
+    DEF_SWI_FLAG(CLOSEDIR,         0x181) \
+    DEF_SWI_FLAG(READDIR,          0x182) \
+    DEF_SWI_FLAG(EXEC,             0x185) \
+    DEF_SWI_FLAG(FTRUNC,           0x186)
+
+/*
+ * We use the arm-compatible semihosting routines for these ones, but we do
+ * need some hexagon-specific preprocessing.
+ */
+#define HEX_SYS_WRITE       0x05
+#define HEX_SYS_READ        0x06
+#define HEX_SYS_READC       0x07
+
+#define DEF_SWI_FLAG(name, val) HEX_SYS_ ##name = val,
+enum hex_swi_flag {
+    HEXAGON_SPECIFIC_SWI_FLAGS
+};
+#undef DEF_SWI_FLAG
+
+#define DEF_SWI_FLAG(_, val) case val:
+static inline bool is_hexagon_specific_swi_flag(enum hex_swi_flag what_swi)
+{
+    switch (what_swi) {
+    HEXAGON_SPECIFIC_SWI_FLAGS
+        return true;
+    }
+    return false;
+}
+#undef DEF_SWI_FLAG
+
+static void init_semihosting_guestfds(void)
+{
+    static gsize initialized;
+
+    if (g_once_init_enter(&initialized)) {
+        if (qemu_semihosting_console_has_chardev()) {
+            alloc_guestfd();
+            console_guestfd(0);
+            alloc_guestfd();
+            console_guestfd(1);
+            alloc_guestfd();
+            console_guestfd(2);
+        } else {
+            alloc_guestfd();
+            associate_guestfd(0, 0);
+            alloc_guestfd();
+            associate_guestfd(1, 1);
+            alloc_guestfd();
+            associate_guestfd(2, 2);
+        }
+        g_once_init_leave(&initialized, 1);
+    }
+}
+
+static void do_preload(CPUHexagonState *env, target_ulong swi_info, bool load)
+{
+    uint32_t addr, count;
+    uintptr_t retaddr = 0;
+
+    hexagon_read_memory(env, swi_info + 4, 4, &addr, retaddr);
+    hexagon_read_memory(env, swi_info + 8, 4, &count, retaddr);
+    hexagon_peek_memory_range(env, addr, count, retaddr);
+}
+
+static void sim_handle_trap0(CPUHexagonState *env)
+{
+    target_ulong what_swi, swi_info;
+    CPUState *cs = env_cpu(env);
+
+    g_assert(bql_locked());
+    init_semihosting_guestfds();
+
+    what_swi = arch_get_thread_reg(env, HEX_REG_R00);
+    swi_info = arch_get_thread_reg(env, HEX_REG_R01);
+
+    qemu_log_mask(CPU_LOG_INT,
+                  "sim_handle_trap0: swi=0x%" PRIx32
+                  " info=0x%" PRIx32 " PC=0x%" PRIx32
+                  " thread=%" PRId32 "\n",
+                  (uint32_t)what_swi, (uint32_t)swi_info,
+                  (uint32_t)arch_get_thread_reg(env, HEX_REG_PC),
+                  (uint32_t)env->threadId);
+
+    if (!is_hexagon_specific_swi_flag(what_swi)) {
+        if (what_swi == HEX_SYS_READ || what_swi == HEX_SYS_READC ||
+            what_swi == HEX_SYS_WRITE) {
+            /*
+             * Avoid page faults if the buffer is not in memory yet.
+             * NOTE: Counterintuitive, but a WRITE must be able to LOAD from
+             * the input address. The contents of that buffer will be
+             * directed to the SWI interface.
+             */
+            do_preload(env, swi_info, (what_swi == HEX_SYS_WRITE));
+        }
+        /*
+         * ARM-compat semihosting SWI numbers are all <= 0x31.
+         * If R0 holds a value outside that range (e.g. guest code
+         * executing trap0(#0) with an arbitrary R0), treat it as an
+         * unrecognized request rather than forwarding to
+         * do_common_semihosting() which would abort.
+         */
+        if (what_swi > 0x31) {
+            qemu_log_mask(LOG_UNIMP,
+                          "trap0(#0): unrecognized request in r0: "
+                          "0x" TARGET_FMT_lx "\n", what_swi);
+            return;
+        }
+        do_common_semihosting(cs);
+        return;
+    }
+
+    switch (what_swi) {
+
+    case HEX_SYS_EXCEPTION:
+    {
+        uint32_t ret = arch_get_thread_reg(env, HEX_REG_R02);
+        arch_set_system_reg(env, HEX_SREG_MODECTL, 0);
+        gdb_exit(ret);
+        exit(ret);
+    }
+    break;
+
+    /* TODO: implement other hexagon-specific semihosting calls */
+
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "unknown swi request: 0x%" PRIx32 "\n",
+                      (uint32_t)what_swi);
+        common_semi_cb(cs, -1, ENOSYS);
+    }
+}
+
 static void set_addresses(CPUHexagonState *env, uint32_t pc_offset,
                           uint32_t exception_index)
-
 {
     HexagonCPU *cpu = env_archcpu(env);
     uint32_t evb = cpu->globalregs ?
@@ -95,8 +257,7 @@ void hexagon_cpu_do_interrupt(CPUState *cs)
     switch (cs->exception_index) {
     case HEX_EVENT_TRAP0:
         if (env->cause_code == 0) {
-            qemu_log_mask(LOG_UNIMP,
-                          "trap0 is unhandled, no semihosting available\n");
+            sim_handle_trap0(env);
         }
 
         hexagon_ssr_set_cause(env, env->cause_code);
diff --git a/hw/hexagon/Kconfig b/hw/hexagon/Kconfig
index 52065ab3b22..3a8ff17812b 100644
--- a/hw/hexagon/Kconfig
+++ b/hw/hexagon/Kconfig
@@ -2,6 +2,7 @@ config HEX_DSP
     bool
     default y
     depends on HEXAGON
+    select ARM_COMPATIBLE_SEMIHOSTING
 
 config HEX_VIRT
     bool
diff --git a/qemu-options.hx b/qemu-options.hx
index 34970fffc94..56f42b02c8a 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -5507,7 +5507,7 @@ 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_RISCV)
+    QEMU_ARCH_MIPS | QEMU_ARCH_RISCV | QEMU_ARCH_HEXAGON)
 SRST
 ``-semihosting``
     Enable :ref:`Semihosting` mode (ARM, M68K, Xtensa, MIPS, RISC-V only).
@@ -5523,11 +5523,11 @@ DEF("semihosting-config", HAS_ARG, QEMU_OPTION_semihosting_config,
     "-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,userspace=on|off][,arg=str[,...]]\n" \
     "                semihosting configuration\n",
 QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA |
-QEMU_ARCH_MIPS | QEMU_ARCH_RISCV)
+QEMU_ARCH_MIPS | QEMU_ARCH_RISCV | QEMU_ARCH_HEXAGON)
 SRST
 ``-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,userspace=on|off][,arg=str[,...]]``
-    Enable and configure :ref:`Semihosting` (ARM, M68K, Xtensa, MIPS, RISC-V
-    only).
+    Enable and configure :ref:`Semihosting` (ARM, M68K, Xtensa, MIPS, RISC-V,
+    Hexagon only).
 
     .. warning::
       Note that this allows guest direct access to the host filesystem, so
diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
index 59cb09c1070..69f01bd2f70 100644
--- a/target/hexagon/meson.build
+++ b/target/hexagon/meson.build
@@ -262,6 +262,9 @@ hexagon_softmmu_ss.add(files(
     'machine.c',
 ))
 
+hexagon_softmmu_ss.add(when: 'CONFIG_ARM_COMPATIBLE_SEMIHOSTING',
+                       if_true: files('common-semi-target.c'))
+
 #
 # Step 4.5
 # We use flex/bison based idef-parser to generate TCG code for a lot
-- 
2.37.2



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

* [PATCH v2 09/14] semihosting: add ftruncate helper (to be used for hexagon)
  2026-07-16 18:06 [PATCH v2 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
                   ` (7 preceding siblings ...)
  2026-07-16 18:06 ` [PATCH v2 08/14] target/hexagon: add semihosting support Matheus Tavares Bernardino
@ 2026-07-16 18:06 ` Matheus Tavares Bernardino
  2026-07-16 18:06 ` [PATCH v2 10/14] target/hexagon: add main arch-specific semihosting operations Matheus Tavares Bernardino
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-16 18:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: brian.cain, pierrick.bouvier, marco.liebel, philmd, ale, anjo,
	Alex Bennée

The common semihosting syscall layer has no ftruncate
helper, but the Hexagon semihosting ABI includes an FTRUNC
operation.  Add semihost_sys_ftruncate() so that Hexagon
can delegate to it rather than calling ftruncate directly.

Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
---
 include/semihosting/syscalls.h |  2 ++
 semihosting/syscalls.c         | 29 +++++++++++++++++++++++++++++
 2 files changed, 31 insertions(+)

diff --git a/include/semihosting/syscalls.h b/include/semihosting/syscalls.h
index 03aa45b7bb9..3919ab64c7c 100644
--- a/include/semihosting/syscalls.h
+++ b/include/semihosting/syscalls.h
@@ -75,4 +75,6 @@ void semihost_sys_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete,
 void semihost_sys_poll_one(CPUState *cs, gdb_syscall_complete_cb complete,
                            int fd, GIOCondition cond, int timeout);
 
+void semihost_sys_ftruncate(CPUState *cs, gdb_syscall_complete_cb complete,
+                            int fd, off_t len);
 #endif /* SEMIHOSTING_SYSCALLS_H */
diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c
index 20f155f869a..0456db0befb 100644
--- a/semihosting/syscalls.c
+++ b/semihosting/syscalls.c
@@ -8,10 +8,12 @@
 
 #include "qemu/osdep.h"
 #include "qemu/log.h"
+#include "qemu/error-report.h"
 #include "gdbstub/syscalls.h"
 #include "semihosting/guestfd.h"
 #include "semihosting/syscalls.h"
 #include "semihosting/console.h"
+#include "semihosting/semihost.h"
 #ifdef CONFIG_USER_ONLY
 #include "qemu.h"
 #else
@@ -541,6 +543,13 @@ static void host_poll_one(CPUState *cs, gdb_syscall_complete_cb complete,
 }
 #endif
 
+static void host_ftruncate(CPUState *cs, gdb_syscall_complete_cb complete,
+                           GuestFD *gf, off_t len)
+{
+    int err = ftruncate(gf->hostfd, len);
+    complete(cs, err, err < 0 ? errno : 0);
+}
+
 /*
  * Static file semihosting syscall implementations.
  */
@@ -982,3 +991,23 @@ void semihost_sys_poll_one(CPUState *cs, gdb_syscall_complete_cb complete,
     }
 }
 #endif
+
+void semihost_sys_ftruncate(CPUState *cs, gdb_syscall_complete_cb complete,
+                            int fd, off_t len)
+{
+    GuestFD *gf = get_guestfd(fd);
+    if (!gf) {
+        complete(cs, -1, EBADF);
+        return;
+    }
+
+    switch (gf->type) {
+    case GuestFDHost:
+        host_ftruncate(cs, complete, gf, len);
+        break;
+    default:
+        error_report("ftruncate call not implemented "
+                     "for this semihosting mode.");
+        g_assert_not_reached();
+    }
+}
-- 
2.37.2



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

* [PATCH v2 10/14] target/hexagon: add main arch-specific semihosting operations
  2026-07-16 18:06 [PATCH v2 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
                   ` (8 preceding siblings ...)
  2026-07-16 18:06 ` [PATCH v2 09/14] semihosting: add ftruncate helper (to be used for hexagon) Matheus Tavares Bernardino
@ 2026-07-16 18:06 ` Matheus Tavares Bernardino
  2026-07-16 18:19   ` Pierrick Bouvier
  2026-07-16 18:06 ` [PATCH v2 11/14] target/hexagon: add COREDUMP semihosting operation Matheus Tavares Bernardino
                   ` (3 subsequent siblings)
  13 siblings, 1 reply; 19+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-16 18:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: brian.cain, pierrick.bouvier, marco.liebel, philmd, ale, anjo,
	Alex Bennée

The Hexagon semihosting ABI extends the arm-compatible set with
operations like OPEN, WRITECREG, WRITE0, ISTTY, STAT, FSTAT, FTELL,
SEEK, FTRUNC, ACCESS, and GETCWD. Implement these trap0 handlers so
that baremetal programs using the standard Hexagon simulator ABI can
perform file I/O when running on qemu-system-hexagon.

Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
---
 include/semihosting/common-semi.h |   1 +
 semihosting/arm-compat-semi.c     |   2 +-
 target/hexagon/hexswi.c           | 298 +++++++++++++++++++++++++++++-
 3 files changed, 299 insertions(+), 2 deletions(-)

diff --git a/include/semihosting/common-semi.h b/include/semihosting/common-semi.h
index a11905ef4ef..1e7699d7bbd 100644
--- a/include/semihosting/common-semi.h
+++ b/include/semihosting/common-semi.h
@@ -34,6 +34,7 @@
 #ifndef COMMON_SEMI_H
 #define COMMON_SEMI_H
 
+void common_semi_cb(CPUState *cs, uint64_t ret, int err);
 void do_common_semihosting(CPUState *cs);
 uint64_t common_semi_arg(CPUState *cs, int argno);
 void common_semi_set_ret(CPUState *cs, uint64_t ret);
diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index c54753f696f..b930a028649 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -229,7 +229,7 @@ static inline uint32_t get_swi_errno(CPUState *cs)
 #endif
 }
 
-static void common_semi_cb(CPUState *cs, uint64_t ret, int err)
+void common_semi_cb(CPUState *cs, uint64_t ret, int err)
 {
     if (err) {
 #ifdef CONFIG_USER_ONLY
diff --git a/target/hexagon/hexswi.c b/target/hexagon/hexswi.c
index 2aedd8368e2..6efc00fedf9 100644
--- a/target/hexagon/hexswi.c
+++ b/target/hexagon/hexswi.c
@@ -85,6 +85,41 @@ static inline bool is_hexagon_specific_swi_flag(enum hex_swi_flag what_swi)
 }
 #undef DEF_SWI_FLAG
 
+static const unsigned int angel_to_host_filemode_table[] = {
+    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_APPEND | O_CREAT,
+    O_WRONLY | O_APPEND | O_CREAT | O_BINARY,
+    O_RDWR | O_APPEND | O_CREAT,
+    O_RDWR | O_APPEND | O_CREAT | O_BINARY,
+    O_RDWR | O_CREAT,
+    O_RDWR | O_CREAT | O_EXCL
+};
+
+/*
+ * This must match the caller's definition, it would be in the
+ * caller's angel.h or equivalent header.
+ */
+struct __SYS_STAT {
+    uint64_t dev;
+    uint64_t ino;
+    uint32_t mode;
+    uint32_t nlink;
+    uint64_t rdev;
+    uint32_t size;
+    uint32_t __pad1;
+    uint32_t atime;
+    uint32_t mtime;
+    uint32_t ctime;
+    uint32_t __pad2;
+} sys_stat;
+
 static void init_semihosting_guestfds(void)
 {
     static gsize initialized;
@@ -119,10 +154,19 @@ static void do_preload(CPUHexagonState *env, target_ulong swi_info, bool load)
     hexagon_peek_memory_range(env, addr, count, retaddr);
 }
 
+static void common_semi_ftell_cb(CPUState *cs, uint64_t ret, int err)
+{
+    if (err) {
+        ret = -1;
+    }
+    common_semi_cb(cs, ret, err);
+}
+
 static void sim_handle_trap0(CPUHexagonState *env)
 {
     target_ulong what_swi, swi_info;
     CPUState *cs = env_cpu(env);
+    uintptr_t retaddr = 0;
 
     g_assert(bql_locked());
     init_semihosting_guestfds();
@@ -177,7 +221,259 @@ static void sim_handle_trap0(CPUHexagonState *env)
     }
     break;
 
-    /* TODO: implement other hexagon-specific semihosting calls */
+    case HEX_SYS_OPEN:
+    {
+        char filename[BUFSIZ];
+        target_ulong physical_filename_addr;
+        unsigned int filemode;
+        int length;
+        int real_openmode;
+        int ret, err = 0;
+        int i = 0;
+
+        hexagon_read_memory(env, swi_info, 4, &physical_filename_addr, retaddr);
+        hexagon_read_memory(env, swi_info + 4, 4, &filemode, retaddr);
+        hexagon_read_memory(env, swi_info + 8, 4, &length, retaddr);
+
+        if (length >= BUFSIZ) {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "%s: filename too large (%d)\n",
+                          __func__, length);
+            common_semi_cb(cs, -1, ENAMETOOLONG);
+            break;
+        }
+
+        do {
+            hexagon_read_memory(env, physical_filename_addr + i, 1, &filename[i],
+                                retaddr);
+            i++;
+        } while (filename[i - 1]);
+
+        /* convert ARM ANGEL filemode into host filemode */
+        if (filemode < ARRAY_SIZE(angel_to_host_filemode_table)) {
+            real_openmode = angel_to_host_filemode_table[filemode];
+        } else {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "%s: invalid OPEN mode: %u\n",
+                          __func__, filemode);
+            common_semi_cb(cs, -1, EINVAL);
+            break;
+        }
+
+        if (strcmp(filename, ":tt") == 0 &&
+            qemu_semihosting_console_has_chardev()) {
+            ret = alloc_guestfd();
+            console_guestfd(ret);
+        } else {
+            ret = open(filename, real_openmode | O_BINARY, 0644);
+
+            if (ret == -1) {
+                err = errno;
+            } else {
+                int guestfd = alloc_guestfd();
+                associate_guestfd(guestfd, ret);
+                ret = guestfd;
+            }
+        }
+        common_semi_cb(cs, ret, err);
+    }
+    break;
+
+    case HEX_SYS_WRITECREG:
+    {
+        char c = swi_info;
+        qemu_semihosting_console_write(&c, 1);
+    }
+    break;
+
+    /*
+     * Hexagon's SYS_ISTTY is a bit different than arm's: we do not return -1
+     * on error, neither errno. So we override with our own implementation.
+     */
+    case HEX_SYS_ISTTY:
+    {
+        int fd;
+        hexagon_read_memory(env, swi_info, 4, &fd, retaddr);
+        common_semi_cb(cs, isatty(fd), 0);
+    }
+    break;
+
+    case HEX_SYS_SEEK:
+    {
+        int fd;
+        target_ulong off;
+        hexagon_read_memory(env, swi_info, 4, &fd, retaddr);
+        hexagon_read_memory(env, swi_info + 4, 4, &off, retaddr);
+        semihost_sys_lseek(env_cpu(env), common_semi_ftell_cb, fd, off,
+                          GDB_SEEK_SET);
+    }
+    break;
+
+    case HEX_SYS_STAT:
+    case HEX_SYS_FSTAT:
+    {
+        struct stat st_buf;
+        uint8_t *st_bufptr = (uint8_t *)&sys_stat;
+        int rc, err = 0;
+        char filename[BUFSIZ];
+        target_ulong physical_filename_addr;
+        target_ulong statBufferAddr;
+        hexagon_read_memory(env, swi_info, 4, &physical_filename_addr, retaddr);
+
+        if (what_swi == HEX_SYS_STAT) {
+            int i = 0;
+            do {
+                hexagon_read_memory(env, physical_filename_addr + i, 1,
+                                    &filename[i], retaddr);
+                i++;
+            } while ((i < BUFSIZ) && filename[i - 1]);
+            rc = stat(filename, &st_buf);
+            err = errno;
+        } else {
+            int fd = physical_filename_addr;
+            GuestFD *gf = get_guestfd(fd);
+            if (!gf || gf->type != GuestFDHost) {
+                qemu_log_mask(LOG_UNIMP,
+                              "fstat semihosting only implemented"
+                              " for native mode\n");
+                g_assert_not_reached();
+            }
+            rc = fstat(gf->hostfd, &st_buf);
+            err = errno;
+        }
+        if (rc == 0) {
+            sys_stat.dev   = st_buf.st_dev;
+            sys_stat.ino   = st_buf.st_ino;
+            sys_stat.mode  = st_buf.st_mode;
+            sys_stat.nlink = (uint32_t) st_buf.st_nlink;
+            sys_stat.rdev  = st_buf.st_rdev;
+            sys_stat.size  = (uint32_t) st_buf.st_size;
+#if defined(__linux__)
+            sys_stat.atime = (uint32_t) st_buf.st_atim.tv_sec;
+            sys_stat.mtime = (uint32_t) st_buf.st_mtim.tv_sec;
+            sys_stat.ctime = (uint32_t) st_buf.st_ctim.tv_sec;
+#elif defined(_WIN32)
+            sys_stat.atime = st_buf.st_atime;
+            sys_stat.mtime = st_buf.st_mtime;
+            sys_stat.ctime = st_buf.st_ctime;
+#endif
+        }
+        hexagon_read_memory(env, swi_info + 4, 4, &statBufferAddr, retaddr);
+
+        for (int i = 0; i < sizeof(sys_stat); i++) {
+            hexagon_write_memory(env, statBufferAddr + i, 1, st_bufptr[i],
+                                 retaddr);
+        }
+        common_semi_cb(cs, rc, rc == 0 ? 0 : err);
+    }
+    break;
+
+    case HEX_SYS_FTRUNC:
+    {
+        int fd;
+        off_t size_limit;
+        hexagon_read_memory(env, swi_info, 4, &fd, retaddr);
+        hexagon_read_memory(env, swi_info + 4, 8, &size_limit, retaddr);
+        semihost_sys_ftruncate(cs, common_semi_cb, fd, size_limit);
+    }
+    break;
+
+    case HEX_SYS_ACCESS:
+    {
+        char filename[BUFSIZ];
+        uint32_t FileNameAddr;
+        uint32_t BufferMode;
+        int rc;
+
+        int i = 0;
+
+        hexagon_read_memory(env, swi_info, 4, &FileNameAddr, retaddr);
+        do {
+            hexagon_read_memory(env, FileNameAddr + i, 1, &filename[i],
+                                retaddr);
+            i++;
+        } while ((i < BUFSIZ) && (filename[i - 1]));
+        filename[i] = 0;
+
+        hexagon_read_memory(env, swi_info + 4, 4, &BufferMode, retaddr);
+
+        rc = access(filename, BufferMode);
+        common_semi_cb(cs, rc,  rc == 0 ? 0 : errno);
+    }
+    break;
+
+    case HEX_SYS_GETCWD:
+    {
+        char cwdPtr[PATH_MAX];
+        uint32_t BufferAddr;
+        uint32_t BufferSize;
+        uint32_t rc = 0, err = 0;
+
+        hexagon_read_memory(env, swi_info, 4, &BufferAddr, retaddr);
+        hexagon_read_memory(env, swi_info + 4, 4, &BufferSize, retaddr);
+
+        if (!getcwd(cwdPtr, PATH_MAX)) {
+            err = errno;
+        } else {
+            size_t cwd_size = strlen(cwdPtr);
+            if (cwd_size > BufferSize) {
+                err = ERANGE;
+            } else {
+                for (int i = 0; i < cwd_size; i++) {
+                    hexagon_write_memory(env, BufferAddr + i, 1,
+                                         (uint64_t)cwdPtr[i], retaddr);
+                }
+                rc = BufferAddr;
+            }
+        }
+        common_semi_cb(cs, rc, rc != 0 ? 0 : err);
+        break;
+    }
+
+    case HEX_SYS_EXEC:
+    {
+        qemu_log_mask(LOG_UNIMP, "SYS_EXEC is deprecated\n");
+        common_semi_cb(cs, -1, ENOSYS);
+    }
+    break;
+
+    case HEX_SYS_FTELL:
+    {
+        int fd;
+        hexagon_read_memory(env, swi_info, 4, &fd, retaddr);
+        semihost_sys_lseek(cs, common_semi_ftell_cb, fd, 0, GDB_SEEK_CUR);
+    }
+    break;
+
+    case HEX_SYS_READ_CYCLES:
+    case HEX_SYS_READ_TCYCLES:
+    case HEX_SYS_READ_ICOUNT:
+    {
+        arch_set_thread_reg(env, HEX_REG_R00, 0);
+        arch_set_thread_reg(env, HEX_REG_R01, 0);
+        break;
+    }
+
+    case HEX_SYS_READ_PCYCLES:
+    {
+        arch_set_thread_reg(env, HEX_REG_R00,
+            arch_get_system_reg(env, HEX_SREG_PCYCLELO));
+        arch_set_thread_reg(env, HEX_REG_R01,
+            arch_get_system_reg(env, HEX_SREG_PCYCLEHI));
+        break;
+    }
+
+    case HEX_SYS_PROF_ON:
+    case HEX_SYS_PROF_OFF:
+    case HEX_SYS_PROF_STATSRESET:
+    case HEX_SYS_DUMP_PMU_STATS:
+    case HEX_SYS_HEAPINFO:
+        common_semi_cb(cs, -1, ENOSYS);
+        qemu_log_mask(LOG_UNIMP,
+                      "SWI call %" PRIx32
+                      " is unimplemented in QEMU\n",
+                      (uint32_t)what_swi);
+        break;
 
     default:
         qemu_log_mask(LOG_GUEST_ERROR,
-- 
2.37.2



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

* [PATCH v2 11/14] target/hexagon: add COREDUMP semihosting operation
  2026-07-16 18:06 [PATCH v2 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
                   ` (9 preceding siblings ...)
  2026-07-16 18:06 ` [PATCH v2 10/14] target/hexagon: add main arch-specific semihosting operations Matheus Tavares Bernardino
@ 2026-07-16 18:06 ` Matheus Tavares Bernardino
  2026-07-16 18:06 ` [PATCH v2 12/14] target/hexagon: Add an errno mapping Matheus Tavares Bernardino
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-16 18:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: brian.cain, pierrick.bouvier, marco.liebel, philmd, ale, anjo

Baremetal Hexagon programs invoke SYS_COREDUMP (0xCD)
through semihosting to dump CPU state on a fatal exception.
Implement the handler to decode the SSR cause field and
print the full register file, matching hexagon-sim behavior.

Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
---
 target/hexagon/internal.h |   1 +
 target/hexagon/cpu.c      |   2 +-
 target/hexagon/hexswi.c   | 143 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 145 insertions(+), 1 deletion(-)

diff --git a/target/hexagon/internal.h b/target/hexagon/internal.h
index 00b37aea7af..05d1129916e 100644
--- a/target/hexagon/internal.h
+++ b/target/hexagon/internal.h
@@ -28,6 +28,7 @@ int hexagon_hvx_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n);
 void hexagon_debug_vreg(CPUHexagonState *env, int regnum);
 void hexagon_debug_qreg(CPUHexagonState *env, int regnum);
 void hexagon_debug(CPUHexagonState *env);
+void hexagon_dump(CPUHexagonState *env, FILE *f, int flags);
 
 extern const char * const hexagon_regnames[TOTAL_PER_THREAD_REGS];
 #ifndef CONFIG_USER_ONLY
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index 73a799da877..26baf28b607 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -232,7 +232,7 @@ void hexagon_debug_qreg(CPUHexagonState *env, int regnum)
     print_qreg(stdout, env, regnum, false);
 }
 
-static void hexagon_dump(CPUHexagonState *env, FILE *f, int flags)
+void hexagon_dump(CPUHexagonState *env, FILE *f, int flags)
 {
     HexagonCPU *cpu = env_archcpu(env);
 
diff --git a/target/hexagon/hexswi.c b/target/hexagon/hexswi.c
index 6efc00fedf9..564a11e557a 100644
--- a/target/hexagon/hexswi.c
+++ b/target/hexagon/hexswi.c
@@ -162,6 +162,145 @@ static void common_semi_ftell_cb(CPUState *cs, uint64_t ret, int err)
     common_semi_cb(cs, ret, err);
 }
 
+static void coredump(CPUHexagonState *env)
+{
+    uint32_t ssr = arch_get_system_reg(env, HEX_SREG_SSR);
+    FILE *f = qemu_log_trylock();
+
+    if (!f) {
+        return;
+    }
+
+    fprintf(f, "CRASH!\n");
+    fprintf(f, "I think the exception was: ");
+    switch (GET_SSR_FIELD(SSR_CAUSE, ssr)) {
+    case 0x43:
+        fprintf(f, "0x43, NMI");
+        break;
+    case 0x42:
+        fprintf(f, "0x42, Data abort");
+        break;
+    case 0x44:
+        fprintf(f, "0x44, Multi TLB match");
+        break;
+    case HEX_CAUSE_BIU_PRECISE:
+        fprintf(f, "0x%x, Bus Error (Precise BIU error)",
+                HEX_CAUSE_BIU_PRECISE);
+        break;
+    case HEX_CAUSE_DOUBLE_EXCEPT:
+        fprintf(f, "0x%x, Exception observed when EX = 1"
+                " (double exception)",
+                HEX_CAUSE_DOUBLE_EXCEPT);
+        break;
+    case HEX_CAUSE_FETCH_NO_XPAGE:
+        fprintf(f, "0x%x, Privilege violation: User/Guest mode execute"
+                " to page with no execute permissions",
+                HEX_CAUSE_FETCH_NO_XPAGE);
+        break;
+    case HEX_CAUSE_FETCH_NO_UPAGE:
+        fprintf(f, "0x%x, Privilege violation: "
+                "User mode execute to page with no user permissions",
+                HEX_CAUSE_FETCH_NO_UPAGE);
+        break;
+    case HEX_CAUSE_INVALID_PACKET:
+        fprintf(f, "0x%x, Invalid packet",
+                HEX_CAUSE_INVALID_PACKET);
+        break;
+    case HEX_CAUSE_PRIV_USER_NO_GINSN:
+        fprintf(f, "0x%x, Privilege violation:"
+                " guest mode insn in user mode",
+                HEX_CAUSE_PRIV_USER_NO_GINSN);
+        break;
+    case HEX_CAUSE_PRIV_USER_NO_SINSN:
+        fprintf(f, "0x%x, Privilege violation: "
+                "monitor mode insn in user/guest mode",
+                HEX_CAUSE_PRIV_USER_NO_SINSN);
+        break;
+    case HEX_CAUSE_REG_WRITE_CONFLICT:
+        fprintf(f, "0x%x, Multiple writes to same register",
+                HEX_CAUSE_REG_WRITE_CONFLICT);
+        break;
+    case HEX_CAUSE_PC_NOT_ALIGNED:
+        fprintf(f, "0x%x, PC not aligned",
+                HEX_CAUSE_PC_NOT_ALIGNED);
+        break;
+    case HEX_CAUSE_MISALIGNED_LOAD:
+        fprintf(f, "0x%x, Misaligned Load @ 0x%" PRIx32,
+                HEX_CAUSE_MISALIGNED_LOAD,
+                arch_get_system_reg(env, HEX_SREG_BADVA));
+        break;
+    case HEX_CAUSE_MISALIGNED_STORE:
+        fprintf(f, "0x%x, Misaligned Store @ 0x%" PRIx32,
+                HEX_CAUSE_MISALIGNED_STORE,
+                arch_get_system_reg(env, HEX_SREG_BADVA));
+        break;
+    case HEX_CAUSE_PRIV_NO_READ:
+        fprintf(f, "0x%x, Privilege violation: "
+                "user/guest read permission @ 0x%" PRIx32,
+                HEX_CAUSE_PRIV_NO_READ,
+                arch_get_system_reg(env, HEX_SREG_BADVA));
+        break;
+    case HEX_CAUSE_PRIV_NO_WRITE:
+        fprintf(f, "0x%x, Privilege violation: "
+                "user/guest write permission @ 0x%" PRIx32,
+                HEX_CAUSE_PRIV_NO_WRITE,
+                arch_get_system_reg(env, HEX_SREG_BADVA));
+        break;
+    case HEX_CAUSE_PRIV_NO_UREAD:
+        fprintf(f, "0x%x, Privilege violation:"
+                " user read permission @ 0x%" PRIx32,
+                HEX_CAUSE_PRIV_NO_UREAD,
+                arch_get_system_reg(env, HEX_SREG_BADVA));
+        break;
+    case HEX_CAUSE_PRIV_NO_UWRITE:
+        fprintf(f, "0x%x, Privilege violation:"
+                " user write permission @ 0x%" PRIx32,
+                HEX_CAUSE_PRIV_NO_UWRITE,
+                arch_get_system_reg(env, HEX_SREG_BADVA));
+        break;
+    case HEX_CAUSE_COPROC_LDST:
+        fprintf(f, "0x%x, Coprocessor VMEM address error @ 0x%" PRIx32,
+                HEX_CAUSE_COPROC_LDST,
+                arch_get_system_reg(env, HEX_SREG_BADVA));
+        break;
+    case HEX_CAUSE_STACK_LIMIT:
+        fprintf(f, "0x%x, Stack limit check error",
+                HEX_CAUSE_STACK_LIMIT);
+        break;
+    case HEX_CAUSE_FPTRAP_CAUSE_BADFLOAT:
+        fprintf(f, "0x%x, Floating-Point: Execution of Floating-Point "
+                "instruction resulted in exception",
+                HEX_CAUSE_FPTRAP_CAUSE_BADFLOAT);
+        break;
+    case HEX_CAUSE_NO_COPROC_ENABLE:
+        fprintf(f, "0x%x, Illegal Execution of Coprocessor Instruction",
+                HEX_CAUSE_NO_COPROC_ENABLE);
+        break;
+    case HEX_CAUSE_NO_COPROC2_ENABLE:
+        fprintf(f, "0x%x, Illegal Execution of Secondary"
+                " Coprocessor Instruction",
+                HEX_CAUSE_NO_COPROC2_ENABLE);
+        break;
+    case HEX_CAUSE_UNSUPPORTED_HVX_64B:
+        fprintf(f, "0x%x, Unsupported Execution of"
+                " Coprocessor Instruction with 64bits Mode On",
+                HEX_CAUSE_UNSUPPORTED_HVX_64B);
+        break;
+    case HEX_CAUSE_VWCTRL_WINDOW_MISS:
+        fprintf(f, "0x%x, Thread accessing a region"
+                " outside VWCTRL window",
+                HEX_CAUSE_VWCTRL_WINDOW_MISS);
+        break;
+    default:
+        fprintf(f, "unknown cause 0x%" PRIx32,
+                GET_SSR_FIELD(SSR_CAUSE, ssr));
+        break;
+    }
+    fprintf(f, "\nRegister Dump:\n");
+    hexagon_dump(env, f, 0);
+    qemu_log_unlock(f);
+}
+
 static void sim_handle_trap0(CPUHexagonState *env)
 {
     target_ulong what_swi, swi_info;
@@ -437,6 +576,10 @@ static void sim_handle_trap0(CPUHexagonState *env)
     }
     break;
 
+    case HEX_SYS_COREDUMP:
+        coredump(env);
+        break;
+
     case HEX_SYS_FTELL:
     {
         int fd;
-- 
2.37.2



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

* [PATCH v2 12/14] target/hexagon: Add an errno mapping
  2026-07-16 18:06 [PATCH v2 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
                   ` (10 preceding siblings ...)
  2026-07-16 18:06 ` [PATCH v2 11/14] target/hexagon: add COREDUMP semihosting operation Matheus Tavares Bernardino
@ 2026-07-16 18:06 ` Matheus Tavares Bernardino
  2026-07-16 18:06 ` [PATCH v2 13/14] python/machine: support routing semihosting output to the test console Matheus Tavares Bernardino
  2026-07-16 18:06 ` [PATCH v2 14/14] tests/functional: Add hexagon semihosting systests Matheus Tavares Bernardino
  13 siblings, 0 replies; 19+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-16 18:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: brian.cain, pierrick.bouvier, marco.liebel, philmd, ale, anjo

From: Brian Cain <brian.cain@oss.qualcomm.com>

The Hexagon semihosting ABI defines its own errno values
which may differ from the host's.  Translate host errno to
the Hexagon-specific values before returning results to the
guest so that baremetal programs see the expected error codes.

Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
---
 target/hexagon/hexswi.c | 75 ++++++++++++++++++++++++++++++++++-------
 1 file changed, 63 insertions(+), 12 deletions(-)

diff --git a/target/hexagon/hexswi.c b/target/hexagon/hexswi.c
index 564a11e557a..d93789e39c7 100644
--- a/target/hexagon/hexswi.c
+++ b/target/hexagon/hexswi.c
@@ -154,12 +154,63 @@ static void do_preload(CPUHexagonState *env, target_ulong swi_info, bool load)
     hexagon_peek_memory_range(env, addr, count, retaddr);
 }
 
+/* Hexagon semihosting errno values */
+#define HEX_EINVAL          22
+#define HEX_ERRNOS \
+    HEX_ERRNO(EPERM,        1) \
+    HEX_ERRNO(ENOENT,       2) \
+    HEX_ERRNO(EINTR,        4) \
+    HEX_ERRNO(EIO,          5) \
+    HEX_ERRNO(ENXIO,        6) \
+    HEX_ERRNO(EBADF,        9) \
+    HEX_ERRNO(EAGAIN,       11) \
+    HEX_ERRNO(ENOMEM,       12) \
+    HEX_ERRNO(EACCES,       13) \
+    HEX_ERRNO(EFAULT,       14) \
+    HEX_ERRNO(EBUSY,        16) \
+    HEX_ERRNO(EEXIST,       17) \
+    HEX_ERRNO(EXDEV,        18) \
+    HEX_ERRNO(ENODEV,       19) \
+    HEX_ERRNO(ENOTDIR,      20) \
+    HEX_ERRNO(EISDIR,       21) \
+    HEX_ERRNO(EINVAL,       HEX_EINVAL) \
+    HEX_ERRNO(ENFILE,       23) \
+    HEX_ERRNO(EMFILE,       24) \
+    HEX_ERRNO(ENOTTY,       25) \
+    HEX_ERRNO(ETXTBSY,      26) \
+    HEX_ERRNO(EFBIG,        27) \
+    HEX_ERRNO(ENOSPC,       28) \
+    HEX_ERRNO(ESPIPE,       29) \
+    HEX_ERRNO(EROFS,        30) \
+    HEX_ERRNO(EMLINK,       31) \
+    HEX_ERRNO(EPIPE,        32) \
+    HEX_ERRNO(ERANGE,       34) \
+    HEX_ERRNO(ENAMETOOLONG, 36) \
+    HEX_ERRNO(ENOSYS,       38) \
+    HEX_ERRNO(ELOOP,        40) \
+    HEX_ERRNO(EOVERFLOW,    75)
+
+/* Map host errno to hexagon semihosting errno */
+static void semi_cb(CPUState *cs, uint64_t ret, int err)
+{
+#define HEX_ERRNO(NAME, CODE) case NAME: err = CODE; break;
+    switch (err) {
+    case 0:
+        break;
+    HEX_ERRNOS
+    default:
+        err = HEX_EINVAL;
+        break;
+    }
+    common_semi_cb(cs, ret, err);
+}
+
 static void common_semi_ftell_cb(CPUState *cs, uint64_t ret, int err)
 {
     if (err) {
         ret = -1;
     }
-    common_semi_cb(cs, ret, err);
+    semi_cb(cs, ret, err);
 }
 
 static void coredump(CPUHexagonState *env)
@@ -378,7 +429,7 @@ static void sim_handle_trap0(CPUHexagonState *env)
             qemu_log_mask(LOG_GUEST_ERROR,
                           "%s: filename too large (%d)\n",
                           __func__, length);
-            common_semi_cb(cs, -1, ENAMETOOLONG);
+            semi_cb(cs, -1, ENAMETOOLONG);
             break;
         }
 
@@ -395,7 +446,7 @@ static void sim_handle_trap0(CPUHexagonState *env)
             qemu_log_mask(LOG_GUEST_ERROR,
                           "%s: invalid OPEN mode: %u\n",
                           __func__, filemode);
-            common_semi_cb(cs, -1, EINVAL);
+            semi_cb(cs, -1, EINVAL);
             break;
         }
 
@@ -414,7 +465,7 @@ static void sim_handle_trap0(CPUHexagonState *env)
                 ret = guestfd;
             }
         }
-        common_semi_cb(cs, ret, err);
+        semi_cb(cs, ret, err);
     }
     break;
 
@@ -433,7 +484,7 @@ static void sim_handle_trap0(CPUHexagonState *env)
     {
         int fd;
         hexagon_read_memory(env, swi_info, 4, &fd, retaddr);
-        common_semi_cb(cs, isatty(fd), 0);
+        semi_cb(cs, isatty(fd), 0);
     }
     break;
 
@@ -503,7 +554,7 @@ static void sim_handle_trap0(CPUHexagonState *env)
             hexagon_write_memory(env, statBufferAddr + i, 1, st_bufptr[i],
                                  retaddr);
         }
-        common_semi_cb(cs, rc, rc == 0 ? 0 : err);
+        semi_cb(cs, rc, rc == 0 ? 0 : err);
     }
     break;
 
@@ -513,7 +564,7 @@ static void sim_handle_trap0(CPUHexagonState *env)
         off_t size_limit;
         hexagon_read_memory(env, swi_info, 4, &fd, retaddr);
         hexagon_read_memory(env, swi_info + 4, 8, &size_limit, retaddr);
-        semihost_sys_ftruncate(cs, common_semi_cb, fd, size_limit);
+        semihost_sys_ftruncate(cs, semi_cb, fd, size_limit);
     }
     break;
 
@@ -537,7 +588,7 @@ static void sim_handle_trap0(CPUHexagonState *env)
         hexagon_read_memory(env, swi_info + 4, 4, &BufferMode, retaddr);
 
         rc = access(filename, BufferMode);
-        common_semi_cb(cs, rc,  rc == 0 ? 0 : errno);
+        semi_cb(cs, rc,  rc == 0 ? 0 : errno);
     }
     break;
 
@@ -565,14 +616,14 @@ static void sim_handle_trap0(CPUHexagonState *env)
                 rc = BufferAddr;
             }
         }
-        common_semi_cb(cs, rc, rc != 0 ? 0 : err);
+        semi_cb(cs, rc, rc != 0 ? 0 : err);
         break;
     }
 
     case HEX_SYS_EXEC:
     {
         qemu_log_mask(LOG_UNIMP, "SYS_EXEC is deprecated\n");
-        common_semi_cb(cs, -1, ENOSYS);
+        semi_cb(cs, -1, ENOSYS);
     }
     break;
 
@@ -611,7 +662,7 @@ static void sim_handle_trap0(CPUHexagonState *env)
     case HEX_SYS_PROF_STATSRESET:
     case HEX_SYS_DUMP_PMU_STATS:
     case HEX_SYS_HEAPINFO:
-        common_semi_cb(cs, -1, ENOSYS);
+        semi_cb(cs, -1, ENOSYS);
         qemu_log_mask(LOG_UNIMP,
                       "SWI call %" PRIx32
                       " is unimplemented in QEMU\n",
@@ -622,7 +673,7 @@ static void sim_handle_trap0(CPUHexagonState *env)
         qemu_log_mask(LOG_GUEST_ERROR,
                       "unknown swi request: 0x%" PRIx32 "\n",
                       (uint32_t)what_swi);
-        common_semi_cb(cs, -1, ENOSYS);
+        semi_cb(cs, -1, ENOSYS);
     }
 }
 
-- 
2.37.2



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

* [PATCH v2 13/14] python/machine: support routing semihosting output to the test console
  2026-07-16 18:06 [PATCH v2 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
                   ` (11 preceding siblings ...)
  2026-07-16 18:06 ` [PATCH v2 12/14] target/hexagon: Add an errno mapping Matheus Tavares Bernardino
@ 2026-07-16 18:06 ` Matheus Tavares Bernardino
  2026-07-16 18:06 ` [PATCH v2 14/14] tests/functional: Add hexagon semihosting systests Matheus Tavares Bernardino
  13 siblings, 0 replies; 19+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-16 18:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: brian.cain, pierrick.bouvier, marco.liebel, philmd, ale, anjo,
	John Snow, Cleber Rosa

From: Brian Cain <brian.cain@oss.qualcomm.com>

The hexagon semihosting systests will wait for output on the semihosting
console.

Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
---
 python/qemu/machine/machine.py | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/python/qemu/machine/machine.py b/python/qemu/machine/machine.py
index bfb59d4c0bf..39375065558 100644
--- a/python/qemu/machine/machine.py
+++ b/python/qemu/machine/machine.py
@@ -186,6 +186,7 @@ def __init__(self,
         self._console_index = 0
         self._console_set = False
         self._console_device_type: Optional[str] = None
+        self._console_semihosting = False
         self._console_socket: Optional[socket.socket] = None
         self._console_file: Optional[socket.SocketIO] = None
         self._remove_files: List[str] = []
@@ -321,7 +322,10 @@ def _console_args(self, interactive: bool = False) -> List[str]:
             fd = self._cons_sock_pair[0].fileno()
             chardev = f"socket,id=console,fd={fd}"
             args.extend(['-chardev', chardev])
-            if self._console_device_type is None:
+            if self._console_semihosting:
+                args.extend(['-semihosting-config',
+                             'enable=on,chardev=console'])
+            elif self._console_device_type is None:
                 args.extend(['-serial', 'chardev:console'])
             else:
                 device = '%s,chardev=console' % self._console_device_type
@@ -892,7 +896,8 @@ def set_machine(self, machine_type: str) -> None:
 
     def set_console(self,
                     device_type: Optional[str] = None,
-                    console_index: int = 0) -> None:
+                    console_index: int = 0,
+                    semihosting: bool = False) -> None:
         """
         Sets the device type for a console device
 
@@ -921,6 +926,7 @@ def set_console(self,
         self._console_set = True
         self._console_device_type = device_type
         self._console_index = console_index
+        self._console_semihosting = semihosting
 
     @property
     def console_socket(self) -> socket.socket:
-- 
2.37.2



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

* [PATCH v2 14/14] tests/functional: Add hexagon semihosting systests
  2026-07-16 18:06 [PATCH v2 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
                   ` (12 preceding siblings ...)
  2026-07-16 18:06 ` [PATCH v2 13/14] python/machine: support routing semihosting output to the test console Matheus Tavares Bernardino
@ 2026-07-16 18:06 ` Matheus Tavares Bernardino
  13 siblings, 0 replies; 19+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-16 18:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: brian.cain, pierrick.bouvier, marco.liebel, philmd, ale, anjo,
	Thomas Huth, Philippe Mathieu-Daudé, Daniel P. Berrangé

From: Brian Cain <brian.cain@oss.qualcomm.com>

Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
---
 tests/functional/hexagon/meson.build      |   9 ++
 tests/functional/hexagon/test_systests.py | 110 ++++++++++++++++++++++
 tests/functional/meson.build              |   1 +
 3 files changed, 120 insertions(+)
 create mode 100644 tests/functional/hexagon/meson.build
 create mode 100755 tests/functional/hexagon/test_systests.py

diff --git a/tests/functional/hexagon/meson.build b/tests/functional/hexagon/meson.build
new file mode 100644
index 00000000000..6cd684b0df7
--- /dev/null
+++ b/tests/functional/hexagon/meson.build
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+test_hexagon_timeouts = {
+  'systests': 180,
+}
+
+tests_hexagon_system_thorough = [
+  'systests',
+]
diff --git a/tests/functional/hexagon/test_systests.py b/tests/functional/hexagon/test_systests.py
new file mode 100755
index 00000000000..8977aece43d
--- /dev/null
+++ b/tests/functional/hexagon/test_systests.py
@@ -0,0 +1,110 @@
+#!/usr/bin/env python3
+#
+# Copyright(c) Qualcomm Innovation Center, Inc. All Rights Reserved.
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+import re
+import time
+import unittest
+
+from qemu_test import QemuSystemTest, Asset, wait_for_console_pattern
+
+
+_TARBALL_BIN_PATH = (
+    "systests_standalone_package",
+    "StandaloneSysTests_6.4.0.2_v68",
+    "bin",
+)
+
+class SysTestsStandaloneTests(QemuSystemTest):
+    SYSTEST_TIMEOUT_SEC = 30
+
+    ASSET_TARBALL = Asset(
+        "https://github.com/qualcomm/qemu-hexagon-testing/releases/download/v0.2.11/systests_standalone.tar.gz",
+        "b5777aa65245de7710a7a08d717953c1362be7c8b60d9014c9fee8b17610ad1c",
+    )
+
+    def setUp(self):
+        super().setUp()
+        self.archive_extract(self.ASSET_TARBALL)
+
+    def binary(self, name):
+        """Return the full path to binary *name* inside bin dir."""
+        path = self.scratch_file(*_TARBALL_BIN_PATH, name)
+        self.assertTrue(os.path.exists(path))
+        return path
+
+    def run_exit_zero(self, binary_name, *extra_args, machine="V66G_1024"):
+        """Launch *binary_name* and assert it exits with code 0.
+
+        :param binary_name: name of the binary inside bin dir.
+        :param extra_args: optional pairs of (flag, value) strings passed
+            to set_vm_arg(), e.g. ('-append', 'myarg').
+        :param machine: QEMU machine type (default "V66G_1024").
+        """
+        self.set_machine(machine)
+        self.set_vm_arg("-display", "none")
+        self.set_vm_arg("-kernel", self.binary(binary_name))
+        for flag, value in zip(extra_args[::2], extra_args[1::2]):
+            self.set_vm_arg(flag, value)
+        self.vm.launch()
+        self.vm.wait(timeout=60.0)
+        self.assertEqual(self.vm.exitcode(), 0,
+                         f"Test {binary_name} exited with "
+                         f"code {self.vm.exitcode()}, expected 0")
+
+    def run_console_pattern(self, binary_name, pattern, *extra_args,
+                            machine="V66G_1024"):
+        """Launch *binary_name* and wait for *pattern* on the semihosting console.
+
+        :param binary_name: name of the binary inside bin dir.
+        :param pattern: string pattern to wait for via wait_for_console_pattern.
+        :param extra_args: optional pairs of (flag, value) strings passed
+            to set_vm_arg(), e.g. ('-append', 'myarg').
+        :param machine: QEMU machine type (default "V66G_1024").
+        """
+        self.set_machine(machine)
+        self.set_vm_arg("-display", "none")
+        self.set_vm_arg("-kernel", self.binary(binary_name))
+        for flag, value in zip(extra_args[::2], extra_args[1::2]):
+            self.set_vm_arg(flag, value)
+        self.vm.set_console(semihosting=True)
+        self.vm.launch()
+        try:
+            wait_for_console_pattern(self, pattern)
+        finally:
+            self.vm.kill()
+
+    def test_fopen(self):
+        """fopen reads a file passed via --append and verifies its contents."""
+        import tempfile
+        # The fopen binary has a short cmdline buffer; use a short path.
+        dummy = os.path.join(tempfile.gettempdir(), "qemu_fopen_test.so")
+        with open(dummy, "w") as f:
+            f.write("valid\n")
+        self.run_exit_zero("fopen", "-append", dummy)
+
+    def test_ftrunc(self):
+        """ftrunc truncates _testfile_ftrunc from 6 bytes to 1 byte."""
+        ftrunc_path = self.scratch_file("_testfile_ftrunc")
+        with open(ftrunc_path, "w") as f:
+            f.write("valid\n")
+        # Sleep 1 s so mtime change is observable
+        time.sleep(1)
+        self.run_exit_zero("ftrunc", "-append", ftrunc_path)
+        self.assertEqual(os.path.getsize(ftrunc_path), 1,
+                         "_testfile_ftrunc should be 1 byte after ftrunc")
+
+    def test_access(self):
+        """access checks R_OK|W_OK on _testfile_access."""
+        testfile = self.scratch_file("_testfile_access")
+        with open(testfile, "w") as f:
+            f.write("valid\n")
+        self.run_exit_zero("access", "-append", testfile)
+
+    def test_semihost(self):
+        self.run_console_pattern("semihost", "PASS", "-append", "arg1", "arg2")
+
+if __name__ == "__main__":
+    QemuSystemTest.main()
diff --git a/tests/functional/meson.build b/tests/functional/meson.build
index c158197c4b7..c7362dd00ef 100644
--- a/tests/functional/meson.build
+++ b/tests/functional/meson.build
@@ -14,6 +14,7 @@ subdir('aarch64')
 subdir('alpha')
 subdir('arm')
 subdir('avr')
+subdir('hexagon')
 subdir('hppa')
 subdir('i386')
 subdir('loongarch64')
-- 
2.37.2



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

* Re: [PATCH v2 01/14] target/hexagon: fix improper assign of cause code to exception index
  2026-07-16 18:06 ` [PATCH v2 01/14] target/hexagon: fix improper assign of cause code to exception index Matheus Tavares Bernardino
@ 2026-07-16 18:18   ` Pierrick Bouvier
  0 siblings, 0 replies; 19+ messages in thread
From: Pierrick Bouvier @ 2026-07-16 18:18 UTC (permalink / raw)
  To: Matheus Tavares Bernardino, qemu-devel
  Cc: brian.cain, marco.liebel, philmd, ale, anjo

On 7/16/2026 11:06 AM, Matheus Tavares Bernardino wrote:
> hexagon_get_tb_cpu_state() detects a misaligned PC and raises an
> exception, but it passed HEX_CAUSE_PC_NOT_ALIGNED (a cause code) as the
> event argument to hexagon_raise_exception_err(), whose second parameter
> is the event index (it ends up in cs->exception_index). This causes an
> infinite reboot loop when we reache a misaligned PC.
> 
> Similarly, gen_exception_decode_fail() is called with a cause code
> (HEX_CAUSE_INVALID_PACKET) but unconditionally routes it through
> gen_exception(), which treats its argument as an event index and stores
> it directly in cs->exception_index.
> 
> Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
> ---
>  target/hexagon/cpu.c       | 3 ++-
>  target/hexagon/translate.c | 4 ++++
>  2 files changed, 6 insertions(+), 1 deletion(-)
> 

Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>


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

* Re: [PATCH v2 10/14] target/hexagon: add main arch-specific semihosting operations
  2026-07-16 18:06 ` [PATCH v2 10/14] target/hexagon: add main arch-specific semihosting operations Matheus Tavares Bernardino
@ 2026-07-16 18:19   ` Pierrick Bouvier
  0 siblings, 0 replies; 19+ messages in thread
From: Pierrick Bouvier @ 2026-07-16 18:19 UTC (permalink / raw)
  To: Matheus Tavares Bernardino, qemu-devel
  Cc: brian.cain, marco.liebel, philmd, ale, anjo, Alex Bennée

On 7/16/2026 11:06 AM, Matheus Tavares Bernardino wrote:
> The Hexagon semihosting ABI extends the arm-compatible set with
> operations like OPEN, WRITECREG, WRITE0, ISTTY, STAT, FSTAT, FTELL,
> SEEK, FTRUNC, ACCESS, and GETCWD. Implement these trap0 handlers so
> that baremetal programs using the standard Hexagon simulator ABI can
> perform file I/O when running on qemu-system-hexagon.
> 
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
> ---
>  include/semihosting/common-semi.h |   1 +
>  semihosting/arm-compat-semi.c     |   2 +-
>  target/hexagon/hexswi.c           | 298 +++++++++++++++++++++++++++++-
>  3 files changed, 299 insertions(+), 2 deletions(-)
> 

Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>


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

* Re: [PATCH v2 08/14] target/hexagon: add semihosting support
  2026-07-16 18:06 ` [PATCH v2 08/14] target/hexagon: add semihosting support Matheus Tavares Bernardino
@ 2026-07-16 21:08   ` Brian Cain
  2026-07-17 11:46     ` Matheus Tavares Bernardino
  0 siblings, 1 reply; 19+ messages in thread
From: Brian Cain @ 2026-07-16 21:08 UTC (permalink / raw)
  To: Matheus Tavares Bernardino, qemu-devel
  Cc: pierrick.bouvier, marco.liebel, philmd, ale, anjo, Paolo Bonzini


On 7/16/2026 1:06 PM, Matheus Tavares Bernardino wrote:
> Baremetal Hexagon programs use trap0 #0 to invoke
> semihosting calls for I/O and process control.  Wire up the
> arm-compatible semihosting framework for softmmu by enabling
> CONFIG_ARM_COMPATIBLE_SEMIHOSTING and routing trap0 to the
> semihosting handler.
>
> Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
> ---
>   docs/system/target-hexagon.rst      |   8 +-
>   configs/targets/hexagon-softmmu.mak |   2 +
>   hw/hexagon/hexagon_dsp.c            |   2 +
>   target/hexagon/common-semi-target.c |  51 +++++++++
>   target/hexagon/hexswi.c             | 167 +++++++++++++++++++++++++++-
>   hw/hexagon/Kconfig                  |   1 +
>   qemu-options.hx                     |   8 +-
>   target/hexagon/meson.build          |   3 +
>   8 files changed, 232 insertions(+), 10 deletions(-)
>   create mode 100644 target/hexagon/common-semi-target.c
>
> diff --git a/docs/system/target-hexagon.rst b/docs/system/target-hexagon.rst
> index 416b8f7be76..36115137626 100644
> --- a/docs/system/target-hexagon.rst
> +++ b/docs/system/target-hexagon.rst
> @@ -91,9 +91,11 @@ Semihosting
>   -----------
>   Hexagon supports a semihosting interface similar to other architectures'.
>   The ``trap0`` instruction can activate these semihosting calls so that the
> -guest software can access the host console and filesystem.  Semihosting
> -is not yet implemented in QEMU hexagon.
> -
> +guest software can access the host console and filesystem. Read the
> +`Hexagon Semihosting Specification
> +<https://docs.qualcomm.com/doc/80-N2040-101_102648/topic/semihosting-specification.html>`__
> +for details. Semihosting is enabled on qemu-system-hexagon machines by default,

It's enabled on most of them, but not `virt`.  So probably mention that 
exception or just describe it as being enabled on the "hexagon-sim-style 
machines"?


> +and it can be configured through ``-semihosting-config``.
>   
>   Hexagon Features
>   ================
> diff --git a/configs/targets/hexagon-softmmu.mak b/configs/targets/hexagon-softmmu.mak
> index a77c100f0c5..6cbdc64be56 100644
> --- a/configs/targets/hexagon-softmmu.mak
> +++ b/configs/targets/hexagon-softmmu.mak
> @@ -6,3 +6,5 @@ TARGET_LONG_BITS=32
>   TARGET_NOT_USING_LEGACY_LDST_PHYS_API=y
>   TARGET_NOT_USING_LEGACY_NATIVE_ENDIAN_API=y
>   TARGET_NEED_FDT=y
> +CONFIG_SEMIHOSTING=y
> +CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
> diff --git a/hw/hexagon/hexagon_dsp.c b/hw/hexagon/hexagon_dsp.c
> index aa493993229..315733cded3 100644
> --- a/hw/hexagon/hexagon_dsp.c
> +++ b/hw/hexagon/hexagon_dsp.c
> @@ -27,6 +27,7 @@
>   #include "target/hexagon/internal.h"
>   #include "system/physmem.h"
>   #include "system/reset.h"
> +#include "semihosting/semihost.h"
>   
>   #include "machine_cfg_v66g_1024.h.inc"
>   
> @@ -178,6 +179,7 @@ static void init_mc(MachineClass *mc)
>       mc->no_serial = 1;
>       mc->is_default = false;
>       mc->max_cpus = 8;
> +    qemu_semihosting_enable();
>   }
>   
>   /* ----------------------------------------------------------------- */
> diff --git a/target/hexagon/common-semi-target.c b/target/hexagon/common-semi-target.c
> new file mode 100644
> index 00000000000..9a7720514bb
> --- /dev/null
> +++ b/target/hexagon/common-semi-target.c
> @@ -0,0 +1,51 @@
> +/*
> + * Target-specific parts of semihosting/arm-compat-semi.c.
> + *
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#include "qemu/osdep.h"
> +#include "cpu.h"
> +#include "cpu_helper.h"
> +#include "semihosting/common-semi.h"
> +
> +uint64_t common_semi_arg(CPUState *cs, int argno)
> +{
> +    CPUHexagonState *env = cpu_env(cs);
> +    return arch_get_thread_reg(env, HEX_REG_R00 + argno);
> +}
> +
> +void common_semi_set_ret(CPUState *cs, uint64_t ret)
> +{
> +    CPUHexagonState *env = cpu_env(cs);
> +    arch_set_thread_reg(env, HEX_REG_R00, ret);
> +}
> +
> +void common_semi_set_err(CPUState *cs, int err)
> +{
> +    CPUHexagonState *env = cpu_env(cs);
> +    arch_set_thread_reg(env, HEX_REG_R01, err);
> +}
> +
> +bool common_semi_sys_exit_is_extended(CPUState *cs)
> +{
> +    return false;
> +}
> +
> +bool is_64bit_semihosting(CPUArchState *env)
> +{
> +    return false;
> +}
> +
> +uint64_t common_semi_stack_bottom(CPUState *cs)
> +{
> +    CPUHexagonState *env = cpu_env(cs);
> +    return arch_get_thread_reg(env, HEX_REG_SP);
> +}
> +
> +bool common_semi_has_synccache(CPUArchState *env)
> +{
> +    return false;
> +}
> diff --git a/target/hexagon/hexswi.c b/target/hexagon/hexswi.c
> index 43c373ea2ee..2aedd8368e2 100644
> --- a/target/hexagon/hexswi.c
> +++ b/target/hexagon/hexswi.c
> @@ -24,9 +24,171 @@
>   #error "This file is only used in system emulation"
>   #endif
>   
> +#include "semihosting/common-semi.h"
> +#include "semihosting/console.h"
> +#include "semihosting/syscalls.h"
> +#include "semihosting/guestfd.h"
> +#include "system/runstate.h"
> +
> +/* non-arm-compatible semihosting calls */
> +#define HEXAGON_SPECIFIC_SWI_FLAGS \
> +    DEF_SWI_FLAG(OPEN,             0x01) \
> +    DEF_SWI_FLAG(ISTTY,            0x09) \
> +    DEF_SWI_FLAG(HEAPINFO,         0x16) \
> +    DEF_SWI_FLAG(EXCEPTION,        0x18) \
> +    DEF_SWI_FLAG(SEEK,             0x0A) \
> +    DEF_SWI_FLAG(READ_CYCLES,      0x40) \
> +    DEF_SWI_FLAG(PROF_ON,          0x41) \
> +    DEF_SWI_FLAG(PROF_OFF,         0x42) \
> +    DEF_SWI_FLAG(WRITECREG,        0x43) \
> +    DEF_SWI_FLAG(READ_TCYCLES,     0x44) \
> +    DEF_SWI_FLAG(LOG_EVENT,        0x45) \
> +    DEF_SWI_FLAG(REDRAW,           0x46) \
> +    DEF_SWI_FLAG(READ_ICOUNT,      0x47) \
> +    DEF_SWI_FLAG(PROF_STATSRESET,  0x48) \
> +    DEF_SWI_FLAG(DUMP_PMU_STATS,   0x4a) \
> +    DEF_SWI_FLAG(READ_PCYCLES,     0x52) \
> +    DEF_SWI_FLAG(COREDUMP,         0xCD) \
> +    DEF_SWI_FLAG(FTELL,            0x100) \
> +    DEF_SWI_FLAG(FSTAT,            0x101) \
> +    DEF_SWI_FLAG(STAT,             0x103) \
> +    DEF_SWI_FLAG(GETCWD,           0x104) \
> +    DEF_SWI_FLAG(ACCESS,           0x105) \
> +    DEF_SWI_FLAG(OPENDIR,          0x180) \
> +    DEF_SWI_FLAG(CLOSEDIR,         0x181) \
> +    DEF_SWI_FLAG(READDIR,          0x182) \
> +    DEF_SWI_FLAG(EXEC,             0x185) \
> +    DEF_SWI_FLAG(FTRUNC,           0x186)
> +
> +/*
> + * We use the arm-compatible semihosting routines for these ones, but we do
> + * need some hexagon-specific preprocessing.
> + */
> +#define HEX_SYS_WRITE       0x05
> +#define HEX_SYS_READ        0x06
> +#define HEX_SYS_READC       0x07
> +
> +#define DEF_SWI_FLAG(name, val) HEX_SYS_ ##name = val,
> +enum hex_swi_flag {
> +    HEXAGON_SPECIFIC_SWI_FLAGS
> +};
> +#undef DEF_SWI_FLAG
> +
> +#define DEF_SWI_FLAG(_, val) case val:
> +static inline bool is_hexagon_specific_swi_flag(enum hex_swi_flag what_swi)
> +{
> +    switch (what_swi) {
> +    HEXAGON_SPECIFIC_SWI_FLAGS
> +        return true;
> +    }
> +    return false;
> +}
> +#undef DEF_SWI_FLAG
> +
> +static void init_semihosting_guestfds(void)
> +{
> +    static gsize initialized;
> +
> +    if (g_once_init_enter(&initialized)) {
> +        if (qemu_semihosting_console_has_chardev()) {
> +            alloc_guestfd();
> +            console_guestfd(0);
> +            alloc_guestfd();
> +            console_guestfd(1);
> +            alloc_guestfd();
> +            console_guestfd(2);
> +        } else {
> +            alloc_guestfd();
> +            associate_guestfd(0, 0);
> +            alloc_guestfd();
> +            associate_guestfd(1, 1);
> +            alloc_guestfd();
> +            associate_guestfd(2, 2);
> +        }
> +        g_once_init_leave(&initialized, 1);
> +    }
> +}
> +
> +static void do_preload(CPUHexagonState *env, target_ulong swi_info, bool load)
> +{
> +    uint32_t addr, count;
> +    uintptr_t retaddr = 0;
> +
> +    hexagon_read_memory(env, swi_info + 4, 4, &addr, retaddr);
> +    hexagon_read_memory(env, swi_info + 8, 4, &count, retaddr);
> +    hexagon_peek_memory_range(env, addr, count, retaddr);
> +}
> +
> +static void sim_handle_trap0(CPUHexagonState *env)
> +{
> +    target_ulong what_swi, swi_info;
> +    CPUState *cs = env_cpu(env);
> +
> +    g_assert(bql_locked());
> +    init_semihosting_guestfds();
> +
> +    what_swi = arch_get_thread_reg(env, HEX_REG_R00);
> +    swi_info = arch_get_thread_reg(env, HEX_REG_R01);
> +
> +    qemu_log_mask(CPU_LOG_INT,
> +                  "sim_handle_trap0: swi=0x%" PRIx32
> +                  " info=0x%" PRIx32 " PC=0x%" PRIx32
> +                  " thread=%" PRId32 "\n",
> +                  (uint32_t)what_swi, (uint32_t)swi_info,
> +                  (uint32_t)arch_get_thread_reg(env, HEX_REG_PC),
> +                  (uint32_t)env->threadId);
> +
> +    if (!is_hexagon_specific_swi_flag(what_swi)) {
> +        if (what_swi == HEX_SYS_READ || what_swi == HEX_SYS_READC ||
> +            what_swi == HEX_SYS_WRITE) {
> +            /*
> +             * Avoid page faults if the buffer is not in memory yet.
> +             * NOTE: Counterintuitive, but a WRITE must be able to LOAD from
> +             * the input address. The contents of that buffer will be
> +             * directed to the SWI interface.
> +             */
> +            do_preload(env, swi_info, (what_swi == HEX_SYS_WRITE));
> +        }
> +        /*
> +         * ARM-compat semihosting SWI numbers are all <= 0x31.
> +         * If R0 holds a value outside that range (e.g. guest code
> +         * executing trap0(#0) with an arbitrary R0), treat it as an
> +         * unrecognized request rather than forwarding to
> +         * do_common_semihosting() which would abort.
> +         */
> +        if (what_swi > 0x31) {
> +            qemu_log_mask(LOG_UNIMP,
> +                          "trap0(#0): unrecognized request in r0: "
> +                          "0x" TARGET_FMT_lx "\n", what_swi);
> +            return;
> +        }
> +        do_common_semihosting(cs);
> +        return;
> +    }
> +
> +    switch (what_swi) {
> +
> +    case HEX_SYS_EXCEPTION:
> +    {
> +        uint32_t ret = arch_get_thread_reg(env, HEX_REG_R02);
> +        arch_set_system_reg(env, HEX_SREG_MODECTL, 0);
> +        gdb_exit(ret);
> +        exit(ret);
> +    }
> +    break;
> +
> +    /* TODO: implement other hexagon-specific semihosting calls */
> +
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "unknown swi request: 0x%" PRIx32 "\n",
> +                      (uint32_t)what_swi);
> +        common_semi_cb(cs, -1, ENOSYS);
> +    }
> +}
> +
>   static void set_addresses(CPUHexagonState *env, uint32_t pc_offset,
>                             uint32_t exception_index)
> -
>   {
>       HexagonCPU *cpu = env_archcpu(env);
>       uint32_t evb = cpu->globalregs ?
> @@ -95,8 +257,7 @@ void hexagon_cpu_do_interrupt(CPUState *cs)
>       switch (cs->exception_index) {
>       case HEX_EVENT_TRAP0:
>           if (env->cause_code == 0) {
> -            qemu_log_mask(LOG_UNIMP,
> -                          "trap0 is unhandled, no semihosting available\n");
> +            sim_handle_trap0(env);
>           }
>   
>           hexagon_ssr_set_cause(env, env->cause_code);
> diff --git a/hw/hexagon/Kconfig b/hw/hexagon/Kconfig
> index 52065ab3b22..3a8ff17812b 100644
> --- a/hw/hexagon/Kconfig
> +++ b/hw/hexagon/Kconfig
> @@ -2,6 +2,7 @@ config HEX_DSP
>       bool
>       default y
>       depends on HEXAGON
> +    select ARM_COMPATIBLE_SEMIHOSTING
>   
>   config HEX_VIRT
>       bool
> diff --git a/qemu-options.hx b/qemu-options.hx
> index 34970fffc94..56f42b02c8a 100644
> --- a/qemu-options.hx
> +++ b/qemu-options.hx
> @@ -5507,7 +5507,7 @@ 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_RISCV)
> +    QEMU_ARCH_MIPS | QEMU_ARCH_RISCV | QEMU_ARCH_HEXAGON)
>   SRST
>   ``-semihosting``
>       Enable :ref:`Semihosting` mode (ARM, M68K, Xtensa, MIPS, RISC-V only).
> @@ -5523,11 +5523,11 @@ DEF("semihosting-config", HAS_ARG, QEMU_OPTION_semihosting_config,
>       "-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,userspace=on|off][,arg=str[,...]]\n" \
>       "                semihosting configuration\n",
>   QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA |
> -QEMU_ARCH_MIPS | QEMU_ARCH_RISCV)
> +QEMU_ARCH_MIPS | QEMU_ARCH_RISCV | QEMU_ARCH_HEXAGON)
>   SRST
>   ``-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,userspace=on|off][,arg=str[,...]]``
> -    Enable and configure :ref:`Semihosting` (ARM, M68K, Xtensa, MIPS, RISC-V
> -    only).
> +    Enable and configure :ref:`Semihosting` (ARM, M68K, Xtensa, MIPS, RISC-V,
> +    Hexagon only).
>   
>       .. warning::
>         Note that this allows guest direct access to the host filesystem, so
> diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
> index 59cb09c1070..69f01bd2f70 100644
> --- a/target/hexagon/meson.build
> +++ b/target/hexagon/meson.build
> @@ -262,6 +262,9 @@ hexagon_softmmu_ss.add(files(
>       'machine.c',
>   ))
>   
> +hexagon_softmmu_ss.add(when: 'CONFIG_ARM_COMPATIBLE_SEMIHOSTING',
> +                       if_true: files('common-semi-target.c'))
> +
>   #
>   # Step 4.5
>   # We use flex/bison based idef-parser to generate TCG code for a lot


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

* Re: [PATCH v2 08/14] target/hexagon: add semihosting support
  2026-07-16 21:08   ` Brian Cain
@ 2026-07-17 11:46     ` Matheus Tavares Bernardino
  0 siblings, 0 replies; 19+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-17 11:46 UTC (permalink / raw)
  To: brian.cain
  Cc: matheus.bernardino, qemu-devel, pierrick.bouvier, marco.liebel,
	philmd, ale, anjo, pbonzini

On Thu, 16 Jul 2026 16:08:42 -0500 Brian Cain <brian.cain@oss.qualcomm.com> wrote:
>
> On 7/16/2026 1:06 PM, Matheus Tavares Bernardino wrote:
> > [...]
> > diff --git a/docs/system/target-hexagon.rst b/docs/system/target-hexagon.rst
> > index 416b8f7be76..36115137626 100644
> > --- a/docs/system/target-hexagon.rst
> > +++ b/docs/system/target-hexagon.rst
> > @@ -91,9 +91,11 @@ Semihosting
> >   -----------
> >   Hexagon supports a semihosting interface similar to other architectures'.
> >   The ``trap0`` instruction can activate these semihosting calls so that the
> > -guest software can access the host console and filesystem.  Semihosting
> > -is not yet implemented in QEMU hexagon.
> > -
> > +guest software can access the host console and filesystem. Read the
> > +`Hexagon Semihosting Specification
> > +<https://docs.qualcomm.com/doc/80-N2040-101_102648/topic/semihosting-specification.html>`__
> > +for details. Semihosting is enabled on qemu-system-hexagon machines by default,
> 
> It's enabled on most of them, but not `virt`.  So probably mention that 
> exception or just describe it as being enabled on the "hexagon-sim-style 
> machines"?

Ah, right. I'll change that.


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

end of thread, other threads:[~2026-07-17 11:46 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-16 18:06 [PATCH v2 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
2026-07-16 18:06 ` [PATCH v2 01/14] target/hexagon: fix improper assign of cause code to exception index Matheus Tavares Bernardino
2026-07-16 18:18   ` Pierrick Bouvier
2026-07-16 18:06 ` [PATCH v2 02/14] target/hexagon: fix get_phys_addr_debug with in-page offset Matheus Tavares Bernardino
2026-07-16 18:06 ` [PATCH v2 03/14] target/hexagon: fix PC advancement for non-COF TB terminators Matheus Tavares Bernardino
2026-07-16 18:06 ` [PATCH v2 04/14] target/hexagon: add aux functions for guest mem load/store Matheus Tavares Bernardino
2026-07-16 18:06 ` [PATCH v2 05/14] hexagon: cpu_helper: add reg reading/writing helpers Matheus Tavares Bernardino
2026-07-16 18:06 ` [PATCH v2 06/14] semihosting: add APIs for chardev-aware guest fd routing Matheus Tavares Bernardino
2026-07-16 18:06 ` [PATCH v2 07/14] semihosting: add callback to set error Matheus Tavares Bernardino
2026-07-16 18:06 ` [PATCH v2 08/14] target/hexagon: add semihosting support Matheus Tavares Bernardino
2026-07-16 21:08   ` Brian Cain
2026-07-17 11:46     ` Matheus Tavares Bernardino
2026-07-16 18:06 ` [PATCH v2 09/14] semihosting: add ftruncate helper (to be used for hexagon) Matheus Tavares Bernardino
2026-07-16 18:06 ` [PATCH v2 10/14] target/hexagon: add main arch-specific semihosting operations Matheus Tavares Bernardino
2026-07-16 18:19   ` Pierrick Bouvier
2026-07-16 18:06 ` [PATCH v2 11/14] target/hexagon: add COREDUMP semihosting operation Matheus Tavares Bernardino
2026-07-16 18:06 ` [PATCH v2 12/14] target/hexagon: Add an errno mapping Matheus Tavares Bernardino
2026-07-16 18:06 ` [PATCH v2 13/14] python/machine: support routing semihosting output to the test console Matheus Tavares Bernardino
2026-07-16 18:06 ` [PATCH v2 14/14] tests/functional: Add hexagon semihosting systests Matheus Tavares Bernardino

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.