+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