* [PATCH v4 00/14] hexagon: add semihosting support
@ 2026-08-24 15:58 Matheus Tavares Bernardino
2026-08-24 15:58 ` [PATCH v4 01/14] disas/hexagon: honour target byte order when printing instructions Matheus Tavares Bernardino
` (13 more replies)
0 siblings, 14 replies; 18+ messages in thread
From: Matheus Tavares Bernardino @ 2026-08-24 15:58 UTC (permalink / raw)
To: qemu-devel; +Cc: ale, anjo, brian.cain, marco.liebel, philmd, pierrick.bouvier
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/
v2: https://lore.kernel.org/qemu-devel/3cd3a419-ee2c-4d7a-9396-60eab8d26908@oss.qualcomm.com/T/#m9e966877cda81c5661838fedadf4e69bd912cbb5
v3: https://lore.kernel.org/qemu-devel/cover.1784568922.git.matheus.bernardino@oss.qualcomm.com/
Changes in v4:
- Added patches 1 and 2: a couple hexagon fixes for big-endian hosts
- Patch 3: fix unaligned pc reporting on linux-user mode
- Patch 5: fix big-endian issues
- Patch 8 and 11: drop arch_[gs]et_(thread|system)_reg()
- Patch 10: avoid OS-specific ifdefs and fixes for big-endian
- Patch 12: define target errnos in a more readable way
- Patch 14: drop unuseful code comments
Changes in v3:
- Reworded semihosting section at Hexagon docs
- Rebased, added Reviewed-by's, dropped already merged patch
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):
disas/hexagon: honour target byte order when printing instructions
target/hexagon: fix store-conditional on big-endian hosts
target/hexagon: fix improper assign of cause code to exception index
target/hexagon: fix PC advancement for non-COF TB terminators
target/hexagon: add aux functions for guest mem load/store
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
configs/targets/hexagon-softmmu.mak | 2 +
disas/hexagon.c | 6 +-
docs/system/target-hexagon.rst | 8 +-
hw/hexagon/Kconfig | 1 +
hw/hexagon/hexagon_dsp.c | 2 +
include/semihosting/common-semi.h | 2 +
include/semihosting/console.h | 9 +
include/semihosting/guestfd.h | 9 +
include/semihosting/syscalls.h | 2 +
linux-user/hexagon/cpu_loop.c | 5 +-
python/qemu/machine/machine.py | 10 +-
qemu-options.hx | 8 +-
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 | 5 +-
target/hexagon/cpu_helper.c | 100 ++++
target/hexagon/cpu_helper.h | 6 +
target/hexagon/genptr.c | 4 +-
target/hexagon/hexswi.c | 672 +++++++++++++++++++++-
target/hexagon/internal.h | 1 +
target/hexagon/meson.build | 1 +
target/hexagon/translate.c | 17 +-
target/riscv/common-semi-target.c | 4 +
tests/functional/hexagon/meson.build | 5 +
tests/functional/hexagon/test_systests.py | 94 +++
29 files changed, 1046 insertions(+), 27 deletions(-)
create mode 100644 target/hexagon/common-semi-target.c
create mode 100755 tests/functional/hexagon/test_systests.py
Range-diff against v3:
-: ---------- > 1: 16f730778f disas/hexagon: honour target byte order when printing instructions
-: ---------- > 2: 4fc8afeddf target/hexagon: fix store-conditional on big-endian hosts
1: 3f809b51ae ! 3: 5403f0e70b target/hexagon: fix improper assign of cause code to exception index
@@ Commit message
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
+ ## linux-user/hexagon/cpu_loop.c ##
+@@ linux-user/hexagon/cpu_loop.c: void cpu_loop(CPUHexagonState *env)
+ break;
+ case HEX_CAUSE_MISALIGNED_LOAD:
+ case HEX_CAUSE_MISALIGNED_STORE:
++ case HEX_CAUSE_PC_NOT_ALIGNED:
+ force_sig_fault(TARGET_SIGBUS, TARGET_BUS_ADRALN,
+ env->gpr[HEX_REG_PC]);
+ break;
+@@ linux-user/hexagon/cpu_loop.c: void cpu_loop(CPUHexagonState *env)
+ exit(EXIT_FAILURE);
+ }
+ break;
+- case HEX_CAUSE_PC_NOT_ALIGNED:
+- force_sig_fault(TARGET_SIGBUS, TARGET_BUS_ADRALN,
+- env->gpr[HEX_REG_R31]);
+- break;
+ case HEX_CAUSE_INVALID_PACKET:
+ case HEX_CAUSE_REG_WRITE_CONFLICT:
+ force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC,
+
## target/hexagon/cpu.c ##
@@ target/hexagon/cpu.c: static TCGTBCPUState hexagon_get_tb_cpu_state(CPUState *cs)
hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, IS_TIGHT_LOOP, 1);
2: 903af8b645 = 4: c1dad05e0a target/hexagon: fix PC advancement for non-COF TB terminators
3: 334bb76346 ! 5: a1f63c8909 target/hexagon: add aux functions for guest mem load/store
@@ target/hexagon/cpu_helper.c
+#ifndef CONFIG_USER_ONLY
+
+static bool hexagon_read_memory_small(CPUHexagonState *env, target_ulong addr,
-+ int byte_count, unsigned char *dstbuf,
++ int byte_count, uint64_t *data,
+ int mmu_idx, uintptr_t retaddr)
+ {
+ /* handle small sizes */
+ switch (byte_count) {
+ case 1:
-+ *dstbuf = cpu_ldub_mmuidx_ra(env, addr, mmu_idx, retaddr);
++ *data = 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;
++ *data = cpu_lduw_le_mmuidx_ra(env, addr, mmu_idx, retaddr);
++ return true;
+
+ case 4:
-+ if (QEMU_IS_ALIGNED(addr, 4)) {
-+ *(uint32_t *)dstbuf =
-+ cpu_ldl_le_mmuidx_ra(env, addr, mmu_idx, retaddr);
-+ return true;
-+ }
-+ break;
++ *data = cpu_ldl_le_mmuidx_ra(env, addr, mmu_idx, retaddr);
++ return true;
+
+ case 8:
-+ if (QEMU_IS_ALIGNED(addr, 8)) {
-+ *(uint64_t *)dstbuf =
-+ cpu_ldq_le_mmuidx_ra(env, addr, mmu_idx, retaddr);
-+ return true;
-+ }
-+ break;
++ *data = cpu_ldq_le_mmuidx_ra(env, addr, mmu_idx, retaddr);
++ return true;
+
+ 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,
@@ target/hexagon/cpu_helper.c
+ 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)) {
++ uint64_t data;
++ if (hexagon_read_memory_small(env, vaddr, size, &data, mmu_idx, retaddr)) {
++ stn_he_p(retptr, size, data);
++ } else {
+ 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 byte_count, uint64_t data,
+ int mmu_idx, uintptr_t retaddr)
+{
+ /* handle small sizes */
+ switch (byte_count) {
+ case 1:
-+ cpu_stb_mmuidx_ra(env, addr, *srcbuf, mmu_idx, retaddr);
++ cpu_stb_mmuidx_ra(env, addr, (uint8_t)data, 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;
++ cpu_stw_le_mmuidx_ra(env, addr, (uint16_t)data, mmu_idx, retaddr);
++ return true;
+
+ case 4:
-+ if (QEMU_IS_ALIGNED(addr, 4)) {
-+ cpu_stl_le_mmuidx_ra(env, addr, *(uint32_t *)srcbuf, mmu_idx, retaddr);
-+ return true;
-+ }
-+ break;
++ cpu_stl_le_mmuidx_ra(env, addr, (uint32_t)data, mmu_idx, retaddr);
++ return true;
+
+ case 8:
-+ if (QEMU_IS_ALIGNED(addr, 8)) {
-+ cpu_stq_le_mmuidx_ra(env, addr, *(uint64_t *)srcbuf, mmu_idx, retaddr);
-+ return true;
-+ }
-+ break;
++ cpu_stq_le_mmuidx_ra(env, addr, (uint64_t)data, mmu_idx, retaddr);
++ return true;
+
+ 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,
@@ target/hexagon/cpu_helper.c
+{
+ 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)) {
++ if (!hexagon_write_memory_small(env, vaddr, size, data, mmu_idx, retaddr)) {
+ cpu_abort(cs, "%s: ERROR: bad size = %d!\n", __func__, size);
+ }
+}
4: f2fc7ed466 < -: ---------- hexagon: cpu_helper: add reg reading/writing helpers
5: c8f8868aa7 = 6: 47eb2ef70d semihosting: add APIs for chardev-aware guest fd routing
6: ef17701179 = 7: a37971603c semihosting: add callback to set error
7: f0d35e6115 ! 8: 7529648c78 target/hexagon: add semihosting support
@@ target/hexagon/common-semi-target.c (new)
+uint64_t common_semi_arg(CPUState *cs, int argno)
+{
+ CPUHexagonState *env = cpu_env(cs);
-+ return arch_get_thread_reg(env, HEX_REG_R00 + argno);
++ return env->gpr[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);
++ env->gpr[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);
++ env->gpr[HEX_REG_R01] = err;
+}
+
+bool common_semi_sys_exit_is_extended(CPUState *cs)
@@ target/hexagon/common-semi-target.c (new)
+uint64_t common_semi_stack_bottom(CPUState *cs)
+{
+ CPUHexagonState *env = cpu_env(cs);
-+ return arch_get_thread_reg(env, HEX_REG_SP);
++ return env->gpr[HEX_REG_SP];
+}
+
+bool common_semi_has_synccache(CPUArchState *env)
@@ target/hexagon/hexswi.c
+ 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);
++ what_swi = env->gpr[HEX_REG_R00];
++ swi_info = env->gpr[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->gpr[HEX_REG_PC],
+ (uint32_t)env->threadId);
+
+ if (!is_hexagon_specific_swi_flag(what_swi)) {
@@ target/hexagon/hexswi.c
+
+ case HEX_SYS_EXCEPTION:
+ {
-+ uint32_t ret = arch_get_thread_reg(env, HEX_REG_R02);
-+ arch_set_system_reg(env, HEX_SREG_MODECTL, 0);
++ uint32_t ret = env->gpr[HEX_REG_R02];
++ env->gpr[HEX_SREG_MODECTL] = 0;
+ gdb_exit(ret);
+ exit(ret);
+ }
@@ target/hexagon/hexswi.c
+ /* TODO: implement other hexagon-specific semihosting calls */
+
+ default:
-+ qemu_log_mask(LOG_GUEST_ERROR,
++ qemu_log_mask(LOG_UNIMP,
+ "unknown swi request: 0x%" PRIx32 "\n",
+ (uint32_t)what_swi);
+ common_semi_cb(cs, -1, ENOSYS);
@@ target/hexagon/hexswi.c: void hexagon_cpu_do_interrupt(CPUState *cs)
## target/hexagon/meson.build ##
@@ target/hexagon/meson.build: hexagon_softmmu_ss.add(files(
+ 'hex_interrupts.c',
+ 'hexswi.c',
'machine.c',
++ 'common-semi-target.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
8: 35d0c39f75 = 9: 2b36fa4993 semihosting: add ftruncate helper (to be used for hexagon)
9: 924d0069ad ! 10: dde7923648 target/hexagon: add main arch-specific semihosting operations
@@ target/hexagon/hexswi.c: static void sim_handle_trap0(CPUHexagonState *env)
+ 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
++ sys_stat.dev = cpu_to_le64(st_buf.st_dev);
++ sys_stat.ino = cpu_to_le64(st_buf.st_ino);
++ sys_stat.mode = cpu_to_le32(st_buf.st_mode);
++ sys_stat.nlink = cpu_to_le32((uint32_t) st_buf.st_nlink);
++ sys_stat.rdev = cpu_to_le64(st_buf.st_rdev);
++ sys_stat.size = cpu_to_le32((uint32_t) st_buf.st_size);
++ sys_stat.atime = cpu_to_le32(st_buf.st_atime);
++ sys_stat.mtime = cpu_to_le32(st_buf.st_mtime);
++ sys_stat.ctime = cpu_to_le32(st_buf.st_ctime);
+ }
+ hexagon_read_memory(env, swi_info + 4, 4, &statBufferAddr, retaddr);
+
@@ target/hexagon/hexswi.c: static void sim_handle_trap0(CPUHexagonState *env)
+ 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);
++ env->gpr[HEX_REG_R00] = 0;
++ env->gpr[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));
++ env->gpr[HEX_REG_R00] = hexagon_get_sys_pcycle_count_low(env);
++ env->gpr[HEX_REG_R01] = hexagon_get_sys_pcycle_count_high(env);
+ break;
+ }
+
@@ target/hexagon/hexswi.c: static void sim_handle_trap0(CPUHexagonState *env)
+ break;
default:
- qemu_log_mask(LOG_GUEST_ERROR,
+ qemu_log_mask(LOG_UNIMP,
10: a81c46b955 ! 11: 0664a4a5a9 target/hexagon: add COREDUMP semihosting operation
@@ target/hexagon/hexswi.c: static void common_semi_ftell_cb(CPUState *cs, uint64_t
+static void coredump(CPUHexagonState *env)
+{
-+ uint32_t ssr = arch_get_system_reg(env, HEX_SREG_SSR);
++ uint32_t ssr = env->t_sreg[HEX_SREG_SSR];
+ FILE *f = qemu_log_trylock();
+
+ if (!f) {
@@ target/hexagon/hexswi.c: static void common_semi_ftell_cb(CPUState *cs, uint64_t
+ 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));
++ HEX_CAUSE_MISALIGNED_LOAD, env->t_sreg[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));
++ HEX_CAUSE_MISALIGNED_STORE, env->t_sreg[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));
++ HEX_CAUSE_PRIV_NO_READ, env->t_sreg[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));
++ HEX_CAUSE_PRIV_NO_WRITE, env->t_sreg[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));
++ HEX_CAUSE_PRIV_NO_UREAD, env->t_sreg[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));
++ HEX_CAUSE_PRIV_NO_UWRITE, env->t_sreg[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));
++ HEX_CAUSE_COPROC_LDST, env->t_sreg[HEX_SREG_BADVA]);
+ break;
+ case HEX_CAUSE_STACK_LIMIT:
+ fprintf(f, "0x%x, Stack limit check error",
11: 289e5cb2d9 ! 12: 71b686df7f target/hexagon: Add an errno mapping
@@ target/hexagon/hexswi.c: static void do_preload(CPUHexagonState *env, target_ulo
}
+/* 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)
++enum {
++ TARGET_EPERM = 1,
++ TARGET_ENOENT = 2,
++ TARGET_EINTR = 4,
++ TARGET_EIO = 5,
++ TARGET_ENXIO = 6,
++ TARGET_EBADF = 9,
++ TARGET_EAGAIN = 11,
++ TARGET_ENOMEM = 12,
++ TARGET_EACCES = 13,
++ TARGET_EFAULT = 14,
++ TARGET_EBUSY = 16,
++ TARGET_EEXIST = 17,
++ TARGET_EXDEV = 18,
++ TARGET_ENODEV = 19,
++ TARGET_ENOTDIR = 20,
++ TARGET_EISDIR = 21,
++ TARGET_EINVAL = 22,
++ TARGET_ENFILE = 23,
++ TARGET_EMFILE = 24,
++ TARGET_ENOTTY = 25,
++ TARGET_ETXTBSY = 26,
++ TARGET_EFBIG = 27,
++ TARGET_ENOSPC = 28,
++ TARGET_ESPIPE = 29,
++ TARGET_EROFS = 30,
++ TARGET_EMLINK = 31,
++ TARGET_EPIPE = 32,
++ TARGET_ERANGE = 34,
++ TARGET_ENAMETOOLONG = 36,
++ TARGET_ENOSYS = 38,
++ TARGET_ELOOP = 40,
++ TARGET_EOVERFLOW = 75,
++};
+
+/* Map host errno to hexagon semihosting errno */
++static uint32_t errno_h2g(uint32_t err) {
++ switch (err) {
++ case 0: return 0;
++ case EPERM: return TARGET_EPERM;
++ case ENOENT: return TARGET_ENOENT;
++ case EINTR: return TARGET_EINTR;
++ case EIO: return TARGET_EIO;
++ case ENXIO: return TARGET_ENXIO;
++ case EBADF: return TARGET_EBADF;
++ case EAGAIN: return TARGET_EAGAIN;
++ case ENOMEM: return TARGET_ENOMEM;
++ case EACCES: return TARGET_EACCES;
++ case EFAULT: return TARGET_EFAULT;
++ case EBUSY: return TARGET_EBUSY;
++ case EEXIST: return TARGET_EEXIST;
++ case EXDEV: return TARGET_EXDEV;
++ case ENODEV: return TARGET_ENODEV;
++ case ENOTDIR: return TARGET_ENOTDIR;
++ case EISDIR: return TARGET_EISDIR;
++ case EINVAL: return TARGET_EINVAL;
++ case ENFILE: return TARGET_ENFILE;
++ case EMFILE: return TARGET_EMFILE;
++ case ENOTTY: return TARGET_ENOTTY;
++ case ETXTBSY: return TARGET_ETXTBSY;
++ case EFBIG: return TARGET_EFBIG;
++ case ENOSPC: return TARGET_ENOSPC;
++ case ESPIPE: return TARGET_ESPIPE;
++ case EROFS: return TARGET_EROFS;
++ case EMLINK: return TARGET_EMLINK;
++ case EPIPE: return TARGET_EPIPE;
++ case ERANGE: return TARGET_ERANGE;
++ case ENAMETOOLONG: return TARGET_ENAMETOOLONG;
++ case ENOSYS: return TARGET_ENOSYS;
++ case ELOOP: return TARGET_ELOOP;
++ case EOVERFLOW: return TARGET_EOVERFLOW;
++ }
++ return TARGET_EINVAL;
++}
++
+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);
++ common_semi_cb(cs, ret, errno_h2g(err));
+}
+
static void common_semi_ftell_cb(CPUState *cs, uint64_t ret, int err)
@@ target/hexagon/hexswi.c: static void sim_handle_trap0(CPUHexagonState *env)
"SWI call %" PRIx32
" is unimplemented in QEMU\n",
@@ target/hexagon/hexswi.c: static void sim_handle_trap0(CPUHexagonState *env)
- qemu_log_mask(LOG_GUEST_ERROR,
+ qemu_log_mask(LOG_UNIMP,
"unknown swi request: 0x%" PRIx32 "\n",
(uint32_t)what_swi);
- common_semi_cb(cs, -1, ENOSYS);
12: 61d0585371 = 13: abcd31dac2 python/machine: support routing semihosting output to the test console
13: 12b2448ce3 ! 14: 0aab35393d tests/functional: Add hexagon semihosting systests
@@ tests/functional/hexagon/test_systests.py (new)
+ 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))
@@ tests/functional/hexagon/test_systests.py (new)
+
+ 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))
--
2.37.2
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v4 01/14] disas/hexagon: honour target byte order when printing instructions
2026-08-24 15:58 [PATCH v4 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
@ 2026-08-24 15:58 ` Matheus Tavares Bernardino
2026-08-26 22:52 ` Pierrick Bouvier
2026-08-24 15:58 ` [PATCH v4 02/14] target/hexagon: fix store-conditional on big-endian hosts Matheus Tavares Bernardino
` (12 subsequent siblings)
13 siblings, 1 reply; 18+ messages in thread
From: Matheus Tavares Bernardino @ 2026-08-24 15:58 UTC (permalink / raw)
To: qemu-devel; +Cc: ale, anjo, brian.cain, marco.liebel, philmd, pierrick.bouvier
print_insn_hexagon() read each instruction word as a host-order integer,
thus getting them inverted on a big-endian host. Instead, read into a
byte buffer and convert with ldl_le_p().
Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
---
disas/hexagon.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/disas/hexagon.c b/disas/hexagon.c
index e2d3804606..62e0cba661 100644
--- a/disas/hexagon.c
+++ b/disas/hexagon.c
@@ -20,6 +20,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/bswap.h"
#include "disas/dis-asm.h"
#include "target/hexagon/cpu_bits.h"
@@ -37,9 +38,9 @@ int print_insn_hexagon(bfd_vma memaddr, struct disassemble_info *info)
int i, len;
for (i = 0; i < PACKET_WORDS_MAX && !found_end; i++) {
+ bfd_byte insn[sizeof(uint32_t)];
int status = (*info->read_memory_func)(memaddr + i * sizeof(uint32_t),
- (bfd_byte *)&words[i],
- sizeof(uint32_t), info);
+ insn, sizeof(uint32_t), info);
if (status) {
if (i > 0) {
break;
@@ -47,6 +48,7 @@ int print_insn_hexagon(bfd_vma memaddr, struct disassemble_info *info)
(*info->memory_error_func)(status, memaddr, info);
return status;
}
+ words[i] = ldl_le_p(insn);
if (is_packet_end(words[i])) {
found_end = true;
}
--
2.37.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v4 02/14] target/hexagon: fix store-conditional on big-endian hosts
2026-08-24 15:58 [PATCH v4 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
2026-08-24 15:58 ` [PATCH v4 01/14] disas/hexagon: honour target byte order when printing instructions Matheus Tavares Bernardino
@ 2026-08-24 15:58 ` Matheus Tavares Bernardino
2026-08-26 22:53 ` Pierrick Bouvier
2026-08-24 15:58 ` [PATCH v4 03/14] target/hexagon: fix improper assign of cause code to exception index Matheus Tavares Bernardino
` (11 subsequent siblings)
13 siblings, 1 reply; 18+ messages in thread
From: Matheus Tavares Bernardino @ 2026-08-24 15:58 UTC (permalink / raw)
To: qemu-devel; +Cc: ale, anjo, brian.cain, marco.liebel, philmd, pierrick.bouvier
gen_load_locked4u() and gen_load_locked8u() read guest memory with an
explicit MO_LE, but gen_store_conditional4() and
gen_store_conditional8() are missing that, so we wrongly access guest
memory in host byte order.
Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
---
target/hexagon/genptr.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c
index 2a98b13b71..9330732c99 100644
--- a/target/hexagon/genptr.c
+++ b/target/hexagon/genptr.c
@@ -576,7 +576,7 @@ static inline void gen_store_conditional4(DisasContext *ctx,
zero = tcg_constant_tl(0);
tmp = tcg_temp_new();
tcg_gen_atomic_cmpxchg_tl(tmp, hex_llsc_addr, hex_llsc_val, src,
- ctx->mem_idx, MO_32 | MO_ALIGN);
+ ctx->mem_idx, MO_LE | MO_32 | MO_ALIGN);
tcg_gen_movcond_tl(TCG_COND_EQ, pred, tmp, hex_llsc_val,
one, zero);
tcg_gen_br(done);
@@ -601,7 +601,7 @@ static inline void gen_store_conditional8(DisasContext *ctx,
zero = tcg_constant_i64(0);
tmp = tcg_temp_new_i64();
tcg_gen_atomic_cmpxchg_i64(tmp, hex_llsc_addr, hex_llsc_val_i64, src,
- ctx->mem_idx, MO_64 | MO_ALIGN);
+ ctx->mem_idx, MO_LE | MO_64 | MO_ALIGN);
tcg_gen_movcond_i64(TCG_COND_EQ, tmp, tmp, hex_llsc_val_i64,
one, zero);
tcg_gen_extrl_i64_i32(pred, tmp);
--
2.37.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v4 03/14] target/hexagon: fix improper assign of cause code to exception index
2026-08-24 15:58 [PATCH v4 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
2026-08-24 15:58 ` [PATCH v4 01/14] disas/hexagon: honour target byte order when printing instructions Matheus Tavares Bernardino
2026-08-24 15:58 ` [PATCH v4 02/14] target/hexagon: fix store-conditional on big-endian hosts Matheus Tavares Bernardino
@ 2026-08-24 15:58 ` Matheus Tavares Bernardino
2026-08-24 15:58 ` [PATCH v4 04/14] target/hexagon: fix PC advancement for non-COF TB terminators Matheus Tavares Bernardino
` (10 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: Matheus Tavares Bernardino @ 2026-08-24 15:58 UTC (permalink / raw)
To: qemu-devel; +Cc: ale, anjo, brian.cain, marco.liebel, philmd, pierrick.bouvier
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.
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
---
linux-user/hexagon/cpu_loop.c | 5 +----
target/hexagon/cpu.c | 3 ++-
target/hexagon/translate.c | 4 ++++
3 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/linux-user/hexagon/cpu_loop.c b/linux-user/hexagon/cpu_loop.c
index d7f73439db..d46b922479 100644
--- a/linux-user/hexagon/cpu_loop.c
+++ b/linux-user/hexagon/cpu_loop.c
@@ -78,6 +78,7 @@ void cpu_loop(CPUHexagonState *env)
break;
case HEX_CAUSE_MISALIGNED_LOAD:
case HEX_CAUSE_MISALIGNED_STORE:
+ case HEX_CAUSE_PC_NOT_ALIGNED:
force_sig_fault(TARGET_SIGBUS, TARGET_BUS_ADRALN,
env->gpr[HEX_REG_PC]);
break;
@@ -88,10 +89,6 @@ void cpu_loop(CPUHexagonState *env)
exit(EXIT_FAILURE);
}
break;
- case HEX_CAUSE_PC_NOT_ALIGNED:
- force_sig_fault(TARGET_SIGBUS, TARGET_BUS_ADRALN,
- env->gpr[HEX_REG_R31]);
- break;
case HEX_CAUSE_INVALID_PACKET:
case HEX_CAUSE_REG_WRITE_CONFLICT:
force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC,
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index 7067e5b70f..134fbb2cfa 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -323,7 +323,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 06a8159d28..29821ffe3d 100644
--- a/target/hexagon/translate.c
+++ b/target/hexagon/translate.c
@@ -245,7 +245,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] 18+ messages in thread
* [PATCH v4 04/14] target/hexagon: fix PC advancement for non-COF TB terminators
2026-08-24 15:58 [PATCH v4 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
` (2 preceding siblings ...)
2026-08-24 15:58 ` [PATCH v4 03/14] target/hexagon: fix improper assign of cause code to exception index Matheus Tavares Bernardino
@ 2026-08-24 15:58 ` Matheus Tavares Bernardino
2026-08-24 15:58 ` [PATCH v4 05/14] target/hexagon: add aux functions for guest mem load/store Matheus Tavares Bernardino
` (9 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: Matheus Tavares Bernardino @ 2026-08-24 15:58 UTC (permalink / raw)
To: qemu-devel; +Cc: ale, anjo, brian.cain, marco.liebel, philmd, pierrick.bouvier
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 29821ffe3d..da058fe976 100644
--- a/target/hexagon/translate.c
+++ b/target/hexagon/translate.c
@@ -217,6 +217,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();
}
@@ -293,6 +299,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++) {
@@ -302,6 +309,7 @@ static bool check_for_opcode(Packet *pkt, uint16_t opcode)
}
return false;
}
+#endif
static bool need_slot_cancelled(Packet *pkt)
{
@@ -581,10 +589,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] 18+ messages in thread
* [PATCH v4 05/14] target/hexagon: add aux functions for guest mem load/store
2026-08-24 15:58 [PATCH v4 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
` (3 preceding siblings ...)
2026-08-24 15:58 ` [PATCH v4 04/14] target/hexagon: fix PC advancement for non-COF TB terminators Matheus Tavares Bernardino
@ 2026-08-24 15:58 ` Matheus Tavares Bernardino
2026-08-24 15:58 ` [PATCH v4 06/14] semihosting: add APIs for chardev-aware guest fd routing Matheus Tavares Bernardino
` (8 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: Matheus Tavares Bernardino @ 2026-08-24 15:58 UTC (permalink / raw)
To: qemu-devel; +Cc: ale, anjo, brian.cain, marco.liebel, philmd, pierrick.bouvier
Will be used for semihosting.
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/cpu_helper.c | 100 ++++++++++++++++++++++++++++++++++++
target/hexagon/cpu_helper.h | 6 +++
2 files changed, 106 insertions(+)
diff --git a/target/hexagon/cpu_helper.c b/target/hexagon/cpu_helper.c
index 64c5746c6d..fab9a9d7b1 100644
--- a/target/hexagon/cpu_helper.c
+++ b/target/hexagon/cpu_helper.c
@@ -25,6 +25,106 @@
#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, uint64_t *data,
+ int mmu_idx, uintptr_t retaddr)
+ {
+ /* handle small sizes */
+ switch (byte_count) {
+ case 1:
+ *data = cpu_ldub_mmuidx_ra(env, addr, mmu_idx, retaddr);
+ return true;
+
+ case 2:
+ *data = cpu_lduw_le_mmuidx_ra(env, addr, mmu_idx, retaddr);
+ return true;
+
+ case 4:
+ *data = cpu_ldl_le_mmuidx_ra(env, addr, mmu_idx, retaddr);
+ return true;
+
+ case 8:
+ *data = cpu_ldq_le_mmuidx_ra(env, addr, mmu_idx, retaddr);
+ return true;
+
+ default:
+ /* larger request, handle elsewhere */
+ return false;
+ }
+}
+
+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);
+ uint64_t data;
+ if (hexagon_read_memory_small(env, vaddr, size, &data, mmu_idx, retaddr)) {
+ stn_he_p(retptr, size, data);
+ } else {
+ 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, uint64_t data,
+ int mmu_idx, uintptr_t retaddr)
+{
+ /* handle small sizes */
+ switch (byte_count) {
+ case 1:
+ cpu_stb_mmuidx_ra(env, addr, (uint8_t)data, mmu_idx, retaddr);
+ return true;
+
+ case 2:
+ cpu_stw_le_mmuidx_ra(env, addr, (uint16_t)data, mmu_idx, retaddr);
+ return true;
+
+ case 4:
+ cpu_stl_le_mmuidx_ra(env, addr, (uint32_t)data, mmu_idx, retaddr);
+ return true;
+
+ case 8:
+ cpu_stq_le_mmuidx_ra(env, addr, (uint64_t)data, mmu_idx, retaddr);
+ return true;
+
+ default:
+ /* larger request, handle elsewhere */
+ return false;
+ }
+}
+
+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, 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)
{
diff --git a/target/hexagon/cpu_helper.h b/target/hexagon/cpu_helper.h
index d176750315..ca2e13ab1d 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);
--
2.37.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v4 06/14] semihosting: add APIs for chardev-aware guest fd routing
2026-08-24 15:58 [PATCH v4 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
` (4 preceding siblings ...)
2026-08-24 15:58 ` [PATCH v4 05/14] target/hexagon: add aux functions for guest mem load/store Matheus Tavares Bernardino
@ 2026-08-24 15:58 ` Matheus Tavares Bernardino
2026-08-24 15:58 ` [PATCH v4 07/14] semihosting: add callback to set error Matheus Tavares Bernardino
` (7 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: Matheus Tavares Bernardino @ 2026-08-24 15:58 UTC (permalink / raw)
To: qemu-devel; +Cc: ale, anjo, brian.cain, marco.liebel, philmd, pierrick.bouvier
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 1c12e178ee..d5f149e208 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 a7ea1041ea..76ca0fcf1a 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 91e5d50d50..9d78683356 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 e8f236c690..8b5770bab0 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] 18+ messages in thread
* [PATCH v4 07/14] semihosting: add callback to set error
2026-08-24 15:58 [PATCH v4 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
` (5 preceding siblings ...)
2026-08-24 15:58 ` [PATCH v4 06/14] semihosting: add APIs for chardev-aware guest fd routing Matheus Tavares Bernardino
@ 2026-08-24 15:58 ` Matheus Tavares Bernardino
2026-08-24 15:58 ` [PATCH v4 08/14] target/hexagon: add semihosting support Matheus Tavares Bernardino
` (6 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: Matheus Tavares Bernardino @ 2026-08-24 15:58 UTC (permalink / raw)
To: qemu-devel
Cc: ale, anjo, brian.cain, marco.liebel, philmd, pierrick.bouvier,
Daniel Henrique Barboza
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 aa511a46f4..a11905ef4e 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 5e5f181b90..c54753f696 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 2b77ce9c17..38d52deb3d 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 aeaeb88d53..38a00e160c 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] 18+ messages in thread
* [PATCH v4 08/14] target/hexagon: add semihosting support
2026-08-24 15:58 [PATCH v4 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
` (6 preceding siblings ...)
2026-08-24 15:58 ` [PATCH v4 07/14] semihosting: add callback to set error Matheus Tavares Bernardino
@ 2026-08-24 15:58 ` Matheus Tavares Bernardino
2026-08-24 15:58 ` [PATCH v4 09/14] semihosting: add ftruncate helper (to be used for hexagon) Matheus Tavares Bernardino
` (5 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: Matheus Tavares Bernardino @ 2026-08-24 15:58 UTC (permalink / raw)
To: qemu-devel; +Cc: ale, anjo, brian.cain, marco.liebel, philmd, pierrick.bouvier
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 <brian.cain@oss.qualcomm.com>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Reviewed-by: Brian Cain <brian.cain@oss.qualcomm.com>
Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
---
configs/targets/hexagon-softmmu.mak | 2 +
docs/system/target-hexagon.rst | 8 +-
hw/hexagon/Kconfig | 1 +
hw/hexagon/hexagon_dsp.c | 2 +
qemu-options.hx | 8 +-
target/hexagon/common-semi-target.c | 51 +++++++++
target/hexagon/hexswi.c | 167 +++++++++++++++++++++++++++-
target/hexagon/meson.build | 1 +
8 files changed, 230 insertions(+), 10 deletions(-)
create mode 100644 target/hexagon/common-semi-target.c
diff --git a/configs/targets/hexagon-softmmu.mak b/configs/targets/hexagon-softmmu.mak
index a77c100f0c..6cbdc64be5 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/docs/system/target-hexagon.rst b/docs/system/target-hexagon.rst
index 416b8f7be7..a9f8c29810 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/hw/hexagon/Kconfig b/hw/hexagon/Kconfig
index 83b2763d1e..bb8a254fd2 100644
--- a/hw/hexagon/Kconfig
+++ b/hw/hexagon/Kconfig
@@ -5,6 +5,7 @@ config HEX_DSP
select CPU_CLUSTER
select HEX_L2VIC
select HEX_QTIMER
+ select ARM_COMPATIBLE_SEMIHOSTING
config HEX_VIRT
bool
diff --git a/hw/hexagon/hexagon_dsp.c b/hw/hexagon/hexagon_dsp.c
index 20306c28e7..2198436a44 100644
--- a/hw/hexagon/hexagon_dsp.c
+++ b/hw/hexagon/hexagon_dsp.c
@@ -26,6 +26,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"
@@ -153,6 +154,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/qemu-options.hx b/qemu-options.hx
index 34970fffc9..56f42b02c8 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/common-semi-target.c b/target/hexagon/common-semi-target.c
new file mode 100644
index 0000000000..210d33e54e
--- /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 env->gpr[HEX_REG_R00 + argno];
+}
+
+void common_semi_set_ret(CPUState *cs, uint64_t ret)
+{
+ CPUHexagonState *env = cpu_env(cs);
+ env->gpr[HEX_REG_R00] = ret;
+}
+
+void common_semi_set_err(CPUState *cs, int err)
+{
+ CPUHexagonState *env = cpu_env(cs);
+ env->gpr[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 env->gpr[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 43c373ea2e..a5d56fb844 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 = env->gpr[HEX_REG_R00];
+ swi_info = env->gpr[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)env->gpr[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 = env->gpr[HEX_REG_R02];
+ env->gpr[HEX_SREG_MODECTL] = 0;
+ gdb_exit(ret);
+ exit(ret);
+ }
+ break;
+
+ /* TODO: implement other hexagon-specific semihosting calls */
+
+ default:
+ qemu_log_mask(LOG_UNIMP,
+ "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/target/hexagon/meson.build b/target/hexagon/meson.build
index 4c921eee73..09620de332 100644
--- a/target/hexagon/meson.build
+++ b/target/hexagon/meson.build
@@ -261,6 +261,7 @@ hexagon_softmmu_ss.add(files(
'hex_interrupts.c',
'hexswi.c',
'machine.c',
+ 'common-semi-target.c',
))
#
--
2.37.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v4 09/14] semihosting: add ftruncate helper (to be used for hexagon)
2026-08-24 15:58 [PATCH v4 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
` (7 preceding siblings ...)
2026-08-24 15:58 ` [PATCH v4 08/14] target/hexagon: add semihosting support Matheus Tavares Bernardino
@ 2026-08-24 15:58 ` Matheus Tavares Bernardino
2026-08-24 15:58 ` [PATCH v4 10/14] target/hexagon: add main arch-specific semihosting operations Matheus Tavares Bernardino
` (4 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: Matheus Tavares Bernardino @ 2026-08-24 15:58 UTC (permalink / raw)
To: qemu-devel; +Cc: ale, anjo, brian.cain, marco.liebel, philmd, pierrick.bouvier
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 03aa45b7bb..3919ab64c7 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 20f155f869..0456db0bef 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] 18+ messages in thread
* [PATCH v4 10/14] target/hexagon: add main arch-specific semihosting operations
2026-08-24 15:58 [PATCH v4 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
` (8 preceding siblings ...)
2026-08-24 15:58 ` [PATCH v4 09/14] semihosting: add ftruncate helper (to be used for hexagon) Matheus Tavares Bernardino
@ 2026-08-24 15:58 ` Matheus Tavares Bernardino
2026-08-24 15:58 ` [PATCH v4 11/14] target/hexagon: add COREDUMP semihosting operation Matheus Tavares Bernardino
` (3 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: Matheus Tavares Bernardino @ 2026-08-24 15:58 UTC (permalink / raw)
To: qemu-devel; +Cc: ale, anjo, brian.cain, marco.liebel, philmd, pierrick.bouvier
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>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Reviewed-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 | 290 +++++++++++++++++++++++++++++-
3 files changed, 291 insertions(+), 2 deletions(-)
diff --git a/include/semihosting/common-semi.h b/include/semihosting/common-semi.h
index a11905ef4e..1e7699d7bb 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 c54753f696..b930a02864 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 a5d56fb844..fe588d9489 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,251 @@ 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 = cpu_to_le64(st_buf.st_dev);
+ sys_stat.ino = cpu_to_le64(st_buf.st_ino);
+ sys_stat.mode = cpu_to_le32(st_buf.st_mode);
+ sys_stat.nlink = cpu_to_le32((uint32_t) st_buf.st_nlink);
+ sys_stat.rdev = cpu_to_le64(st_buf.st_rdev);
+ sys_stat.size = cpu_to_le32((uint32_t) st_buf.st_size);
+ sys_stat.atime = cpu_to_le32(st_buf.st_atime);
+ sys_stat.mtime = cpu_to_le32(st_buf.st_mtime);
+ sys_stat.ctime = cpu_to_le32(st_buf.st_ctime);
+ }
+ 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:
+ {
+ env->gpr[HEX_REG_R00] = 0;
+ env->gpr[HEX_REG_R01] = 0;
+ break;
+ }
+
+ case HEX_SYS_READ_PCYCLES:
+ {
+ env->gpr[HEX_REG_R00] = hexagon_get_sys_pcycle_count_low(env);
+ env->gpr[HEX_REG_R01] = hexagon_get_sys_pcycle_count_high(env);
+ 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_UNIMP,
--
2.37.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v4 11/14] target/hexagon: add COREDUMP semihosting operation
2026-08-24 15:58 [PATCH v4 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
` (9 preceding siblings ...)
2026-08-24 15:58 ` [PATCH v4 10/14] target/hexagon: add main arch-specific semihosting operations Matheus Tavares Bernardino
@ 2026-08-24 15:58 ` Matheus Tavares Bernardino
2026-08-24 15:58 ` [PATCH v4 12/14] target/hexagon: Add an errno mapping Matheus Tavares Bernardino
` (2 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: Matheus Tavares Bernardino @ 2026-08-24 15:58 UTC (permalink / raw)
To: qemu-devel; +Cc: ale, anjo, brian.cain, marco.liebel, philmd, pierrick.bouvier
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: 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/cpu.c | 2 +-
target/hexagon/hexswi.c | 136 ++++++++++++++++++++++++++++++++++++++
target/hexagon/internal.h | 1 +
3 files changed, 138 insertions(+), 1 deletion(-)
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index 134fbb2cfa..acb1715a4d 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -235,7 +235,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 fe588d9489..5e7f655a41 100644
--- a/target/hexagon/hexswi.c
+++ b/target/hexagon/hexswi.c
@@ -162,6 +162,138 @@ 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 = env->t_sreg[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, env->t_sreg[HEX_SREG_BADVA]);
+ break;
+ case HEX_CAUSE_MISALIGNED_STORE:
+ fprintf(f, "0x%x, Misaligned Store @ 0x%" PRIx32,
+ HEX_CAUSE_MISALIGNED_STORE, env->t_sreg[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, env->t_sreg[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, env->t_sreg[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, env->t_sreg[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, env->t_sreg[HEX_SREG_BADVA]);
+ break;
+ case HEX_CAUSE_COPROC_LDST:
+ fprintf(f, "0x%x, Coprocessor VMEM address error @ 0x%" PRIx32,
+ HEX_CAUSE_COPROC_LDST, env->t_sreg[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;
@@ -431,6 +563,10 @@ static void sim_handle_trap0(CPUHexagonState *env)
}
break;
+ case HEX_SYS_COREDUMP:
+ coredump(env);
+ break;
+
case HEX_SYS_FTELL:
{
int fd;
diff --git a/target/hexagon/internal.h b/target/hexagon/internal.h
index 00b37aea7a..05d1129916 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
--
2.37.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v4 12/14] target/hexagon: Add an errno mapping
2026-08-24 15:58 [PATCH v4 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
` (10 preceding siblings ...)
2026-08-24 15:58 ` [PATCH v4 11/14] target/hexagon: add COREDUMP semihosting operation Matheus Tavares Bernardino
@ 2026-08-24 15:58 ` Matheus Tavares Bernardino
2026-08-24 15:58 ` [PATCH v4 13/14] python/machine: support routing semihosting output to the test console Matheus Tavares Bernardino
2026-08-24 15:58 ` [PATCH v4 14/14] tests/functional: Add hexagon semihosting systests Matheus Tavares Bernardino
13 siblings, 0 replies; 18+ messages in thread
From: Matheus Tavares Bernardino @ 2026-08-24 15:58 UTC (permalink / raw)
To: qemu-devel; +Cc: ale, anjo, brian.cain, marco.liebel, philmd, pierrick.bouvier
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 | 105 +++++++++++++++++++++++++++++++++++-----
1 file changed, 93 insertions(+), 12 deletions(-)
diff --git a/target/hexagon/hexswi.c b/target/hexagon/hexswi.c
index 5e7f655a41..a50ab22554 100644
--- a/target/hexagon/hexswi.c
+++ b/target/hexagon/hexswi.c
@@ -154,12 +154,93 @@ static void do_preload(CPUHexagonState *env, target_ulong swi_info, bool load)
hexagon_peek_memory_range(env, addr, count, retaddr);
}
+/* Hexagon semihosting errno values */
+enum {
+ TARGET_EPERM = 1,
+ TARGET_ENOENT = 2,
+ TARGET_EINTR = 4,
+ TARGET_EIO = 5,
+ TARGET_ENXIO = 6,
+ TARGET_EBADF = 9,
+ TARGET_EAGAIN = 11,
+ TARGET_ENOMEM = 12,
+ TARGET_EACCES = 13,
+ TARGET_EFAULT = 14,
+ TARGET_EBUSY = 16,
+ TARGET_EEXIST = 17,
+ TARGET_EXDEV = 18,
+ TARGET_ENODEV = 19,
+ TARGET_ENOTDIR = 20,
+ TARGET_EISDIR = 21,
+ TARGET_EINVAL = 22,
+ TARGET_ENFILE = 23,
+ TARGET_EMFILE = 24,
+ TARGET_ENOTTY = 25,
+ TARGET_ETXTBSY = 26,
+ TARGET_EFBIG = 27,
+ TARGET_ENOSPC = 28,
+ TARGET_ESPIPE = 29,
+ TARGET_EROFS = 30,
+ TARGET_EMLINK = 31,
+ TARGET_EPIPE = 32,
+ TARGET_ERANGE = 34,
+ TARGET_ENAMETOOLONG = 36,
+ TARGET_ENOSYS = 38,
+ TARGET_ELOOP = 40,
+ TARGET_EOVERFLOW = 75,
+};
+
+/* Map host errno to hexagon semihosting errno */
+static uint32_t errno_h2g(uint32_t err) {
+ switch (err) {
+ case 0: return 0;
+ case EPERM: return TARGET_EPERM;
+ case ENOENT: return TARGET_ENOENT;
+ case EINTR: return TARGET_EINTR;
+ case EIO: return TARGET_EIO;
+ case ENXIO: return TARGET_ENXIO;
+ case EBADF: return TARGET_EBADF;
+ case EAGAIN: return TARGET_EAGAIN;
+ case ENOMEM: return TARGET_ENOMEM;
+ case EACCES: return TARGET_EACCES;
+ case EFAULT: return TARGET_EFAULT;
+ case EBUSY: return TARGET_EBUSY;
+ case EEXIST: return TARGET_EEXIST;
+ case EXDEV: return TARGET_EXDEV;
+ case ENODEV: return TARGET_ENODEV;
+ case ENOTDIR: return TARGET_ENOTDIR;
+ case EISDIR: return TARGET_EISDIR;
+ case EINVAL: return TARGET_EINVAL;
+ case ENFILE: return TARGET_ENFILE;
+ case EMFILE: return TARGET_EMFILE;
+ case ENOTTY: return TARGET_ENOTTY;
+ case ETXTBSY: return TARGET_ETXTBSY;
+ case EFBIG: return TARGET_EFBIG;
+ case ENOSPC: return TARGET_ENOSPC;
+ case ESPIPE: return TARGET_ESPIPE;
+ case EROFS: return TARGET_EROFS;
+ case EMLINK: return TARGET_EMLINK;
+ case EPIPE: return TARGET_EPIPE;
+ case ERANGE: return TARGET_ERANGE;
+ case ENAMETOOLONG: return TARGET_ENAMETOOLONG;
+ case ENOSYS: return TARGET_ENOSYS;
+ case ELOOP: return TARGET_ELOOP;
+ case EOVERFLOW: return TARGET_EOVERFLOW;
+ }
+ return TARGET_EINVAL;
+}
+
+static void semi_cb(CPUState *cs, uint64_t ret, int err)
+{
+ common_semi_cb(cs, ret, errno_h2g(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)
@@ -371,7 +452,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;
}
@@ -388,7 +469,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;
}
@@ -407,7 +488,7 @@ static void sim_handle_trap0(CPUHexagonState *env)
ret = guestfd;
}
}
- common_semi_cb(cs, ret, err);
+ semi_cb(cs, ret, err);
}
break;
@@ -426,7 +507,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;
@@ -490,7 +571,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;
@@ -500,7 +581,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;
@@ -524,7 +605,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;
@@ -552,14 +633,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;
@@ -596,7 +677,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",
@@ -607,7 +688,7 @@ static void sim_handle_trap0(CPUHexagonState *env)
qemu_log_mask(LOG_UNIMP,
"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] 18+ messages in thread
* [PATCH v4 13/14] python/machine: support routing semihosting output to the test console
2026-08-24 15:58 [PATCH v4 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
` (11 preceding siblings ...)
2026-08-24 15:58 ` [PATCH v4 12/14] target/hexagon: Add an errno mapping Matheus Tavares Bernardino
@ 2026-08-24 15:58 ` Matheus Tavares Bernardino
2026-08-24 21:25 ` Philippe Mathieu-Daudé
2026-08-24 15:58 ` [PATCH v4 14/14] tests/functional: Add hexagon semihosting systests Matheus Tavares Bernardino
13 siblings, 1 reply; 18+ messages in thread
From: Matheus Tavares Bernardino @ 2026-08-24 15:58 UTC (permalink / raw)
To: qemu-devel; +Cc: ale, anjo, brian.cain, marco.liebel, philmd, pierrick.bouvier
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 bfb59d4c0b..3937506555 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] 18+ messages in thread
* [PATCH v4 14/14] tests/functional: Add hexagon semihosting systests
2026-08-24 15:58 [PATCH v4 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
` (12 preceding siblings ...)
2026-08-24 15:58 ` [PATCH v4 13/14] python/machine: support routing semihosting output to the test console Matheus Tavares Bernardino
@ 2026-08-24 15:58 ` Matheus Tavares Bernardino
13 siblings, 0 replies; 18+ messages in thread
From: Matheus Tavares Bernardino @ 2026-08-24 15:58 UTC (permalink / raw)
To: qemu-devel; +Cc: ale, anjo, brian.cain, marco.liebel, philmd, pierrick.bouvier
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 | 5 ++
tests/functional/hexagon/test_systests.py | 94 +++++++++++++++++++++++
2 files changed, 99 insertions(+)
create mode 100755 tests/functional/hexagon/test_systests.py
diff --git a/tests/functional/hexagon/meson.build b/tests/functional/hexagon/meson.build
index 2b5a1a8f26..44053e6467 100644
--- a/tests/functional/hexagon/meson.build
+++ b/tests/functional/hexagon/meson.build
@@ -2,4 +2,9 @@
tests_hexagon_system_thorough = [
'arch_tests',
+ 'systests',
]
+
+test_hexagon_timeouts = {
+ 'systests': 180,
+}
diff --git a/tests/functional/hexagon/test_systests.py b/tests/functional/hexagon/test_systests.py
new file mode 100755
index 0000000000..f36e015f50
--- /dev/null
+++ b/tests/functional/hexagon/test_systests.py
@@ -0,0 +1,94 @@
+#!/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):
+ 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"):
+ 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"):
+ 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()
--
2.37.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH v4 13/14] python/machine: support routing semihosting output to the test console
2026-08-24 15:58 ` [PATCH v4 13/14] python/machine: support routing semihosting output to the test console Matheus Tavares Bernardino
@ 2026-08-24 21:25 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 18+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-08-24 21:25 UTC (permalink / raw)
To: Matheus Tavares Bernardino, qemu-devel
Cc: ale, anjo, brian.cain, marco.liebel, pierrick.bouvier
On 24/8/26 17:58, Matheus Tavares Bernardino wrote:
> 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(-)
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v4 01/14] disas/hexagon: honour target byte order when printing instructions
2026-08-24 15:58 ` [PATCH v4 01/14] disas/hexagon: honour target byte order when printing instructions Matheus Tavares Bernardino
@ 2026-08-26 22:52 ` Pierrick Bouvier
0 siblings, 0 replies; 18+ messages in thread
From: Pierrick Bouvier @ 2026-08-26 22:52 UTC (permalink / raw)
To: Matheus Tavares Bernardino, qemu-devel
Cc: ale, anjo, brian.cain, marco.liebel, philmd
On 8/24/2026 8:58 AM, Matheus Tavares Bernardino wrote:
> print_insn_hexagon() read each instruction word as a host-order integer,
> thus getting them inverted on a big-endian host. Instead, read into a
> byte buffer and convert with ldl_le_p().
>
> Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
> ---
> disas/hexagon.c | 6 ++++--
> 1 file changed, 4 insertions(+), 2 deletions(-)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v4 02/14] target/hexagon: fix store-conditional on big-endian hosts
2026-08-24 15:58 ` [PATCH v4 02/14] target/hexagon: fix store-conditional on big-endian hosts Matheus Tavares Bernardino
@ 2026-08-26 22:53 ` Pierrick Bouvier
0 siblings, 0 replies; 18+ messages in thread
From: Pierrick Bouvier @ 2026-08-26 22:53 UTC (permalink / raw)
To: Matheus Tavares Bernardino, qemu-devel
Cc: ale, anjo, brian.cain, marco.liebel, philmd
On 8/24/2026 8:58 AM, Matheus Tavares Bernardino wrote:
> gen_load_locked4u() and gen_load_locked8u() read guest memory with an
> explicit MO_LE, but gen_store_conditional4() and
> gen_store_conditional8() are missing that, so we wrongly access guest
> memory in host byte order.
>
> Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
> ---
> target/hexagon/genptr.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2026-08-26 22:53 UTC | newest]
Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-24 15:58 [PATCH v4 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
2026-08-24 15:58 ` [PATCH v4 01/14] disas/hexagon: honour target byte order when printing instructions Matheus Tavares Bernardino
2026-08-26 22:52 ` Pierrick Bouvier
2026-08-24 15:58 ` [PATCH v4 02/14] target/hexagon: fix store-conditional on big-endian hosts Matheus Tavares Bernardino
2026-08-26 22:53 ` Pierrick Bouvier
2026-08-24 15:58 ` [PATCH v4 03/14] target/hexagon: fix improper assign of cause code to exception index Matheus Tavares Bernardino
2026-08-24 15:58 ` [PATCH v4 04/14] target/hexagon: fix PC advancement for non-COF TB terminators Matheus Tavares Bernardino
2026-08-24 15:58 ` [PATCH v4 05/14] target/hexagon: add aux functions for guest mem load/store Matheus Tavares Bernardino
2026-08-24 15:58 ` [PATCH v4 06/14] semihosting: add APIs for chardev-aware guest fd routing Matheus Tavares Bernardino
2026-08-24 15:58 ` [PATCH v4 07/14] semihosting: add callback to set error Matheus Tavares Bernardino
2026-08-24 15:58 ` [PATCH v4 08/14] target/hexagon: add semihosting support Matheus Tavares Bernardino
2026-08-24 15:58 ` [PATCH v4 09/14] semihosting: add ftruncate helper (to be used for hexagon) Matheus Tavares Bernardino
2026-08-24 15:58 ` [PATCH v4 10/14] target/hexagon: add main arch-specific semihosting operations Matheus Tavares Bernardino
2026-08-24 15:58 ` [PATCH v4 11/14] target/hexagon: add COREDUMP semihosting operation Matheus Tavares Bernardino
2026-08-24 15:58 ` [PATCH v4 12/14] target/hexagon: Add an errno mapping Matheus Tavares Bernardino
2026-08-24 15:58 ` [PATCH v4 13/14] python/machine: support routing semihosting output to the test console Matheus Tavares Bernardino
2026-08-24 21:25 ` Philippe Mathieu-Daudé
2026-08-24 15:58 ` [PATCH v4 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.