Re: [PATCH v3 07/13] target/hexagon: add semihosting support

Brian Cain <[email protected]>
Newsgroups gmane.comp.emulators.qemu
Message-ID <[email protected]>
On 7/20/2026 12:41 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: Brian Cain <[email protected]>
> Reviewed-by: Pierrick Bouvier <[email protected]>
> Signed-off-by: Matheus Tavares Bernardino <[email protected]>
> ---

Reviewed-by: Brian Cain <[email protected]>

>   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..a9f8c29810e 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 by default on hexagon-sim-compatible
> +machines. This can be further 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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.