* [PATCH 00/14] hexagon: add semihosting support
@ 2026-07-13 20:07 Matheus Tavares Bernardino
2026-07-13 20:07 ` [PATCH 01/14] target/hexagon: fix get_phys_addr_debug with in-page offset Matheus Tavares Bernardino
` (14 more replies)
0 siblings, 15 replies; 37+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-13 20:07 UTC (permalink / raw)
To: qemu-devel; +Cc: brian.cain, pierrick.bouvier, marco.liebel, philmd, ale, anjo
This series adds semihosting support to hexagon system emulation,
together with functional tests for the added operations.
The Hexagon semihosting spec can be found at:
https://docs.qualcomm.com/doc/80-N2040-101_102648/topic/semihosting-specification.html
Brian Cain (4):
semihosting: add APIs for chardev-aware guest fd routing
target/hexagon: Add an errno mapping
python/machine: support routing semihosting output to the test console
tests/functional: Add hexagon semihosting systests
Matheus Tavares Bernardino (10):
target/hexagon: fix get_phys_addr_debug with in-page offset
target/hexagon: fix PC advancement for non-COF TB terminators
target/hexagon: add aux functions for guest mem load/store
hexagon: cpu_helper: add reg reading/writing helpers
semihosting: add callback to set error
target/hexagon: add semihosting support
semihosting: add ftruncate helper (to be used for hexagon)
target/hexagon: add main arch-specific semihosting operations
target/hexagon: add COREDUMP semihosting operation
target/hexagon: add OPEN/READ/CLOSE_DIR semihosting operations
configs/targets/hexagon-softmmu.mak | 2 +
include/semihosting/common-semi.h | 2 +
include/semihosting/console.h | 9 +
include/semihosting/guestfd.h | 9 +
include/semihosting/syscalls.h | 2 +
target/hexagon/cpu.h | 1 +
target/hexagon/cpu_helper.h | 24 +
target/hexagon/internal.h | 1 +
hw/hexagon/hexagon_dsp.c | 7 +
hw/hexagon/virt.c | 5 +
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 | 4 +-
target/hexagon/cpu_helper.c | 173 +++++
target/hexagon/hexswi.c | 728 +++++++++++++++++++++-
target/hexagon/op_helper.c | 18 +-
target/hexagon/translate.c | 13 +-
target/riscv/common-semi-target.c | 4 +
hw/hexagon/Kconfig | 1 +
python/qemu/machine/machine.py | 10 +-
qemu-options.hx | 8 +-
target/hexagon/meson.build | 3 +
tests/functional/hexagon/meson.build | 9 +
tests/functional/hexagon/test_systests.py | 133 ++++
tests/functional/meson.build | 1 +
29 files changed, 1236 insertions(+), 31 deletions(-)
create mode 100644 target/hexagon/common-semi-target.c
create mode 100644 tests/functional/hexagon/meson.build
create mode 100644 tests/functional/hexagon/test_systests.py
--
2.37.2
^ permalink raw reply [flat|nested] 37+ messages in thread
* [PATCH 01/14] target/hexagon: fix get_phys_addr_debug with in-page offset
2026-07-13 20:07 [PATCH 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
@ 2026-07-13 20:07 ` Matheus Tavares Bernardino
2026-07-13 21:41 ` Pierrick Bouvier
2026-07-13 20:07 ` [PATCH 02/14] target/hexagon: fix PC advancement for non-COF TB terminators Matheus Tavares Bernardino
` (13 subsequent siblings)
14 siblings, 1 reply; 37+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-13 20:07 UTC (permalink / raw)
To: qemu-devel; +Cc: brian.cain, pierrick.bouvier, marco.liebel, philmd, ale, anjo
As documented:
* @get_phys_addr_debug: Callback for obtaining a physical address.
* This must be able to handle a non-page-aligned address, and will
* return the physical address corresponding to that address.
When MMU is enabled, hexagon_cpu_get_phys_addr_debug() returns the
physical address page-aligned, not corrected to reflect the exact byte
the virtual addr maps to within the page. Let's fix that. The
MMU-disabled case is already correct.
This would break semihosting argument reads when it is added for Hexagon.
Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
---
target/hexagon/cpu.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index 42d93e5da47..028cfe9edde 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -569,7 +569,9 @@ static hwaddr hexagon_cpu_get_phys_addr_debug(CPUState *cs, vaddr addr)
if (get_physical_address(env, &phys_addr, &prot, &page_size, &excp,
addr, 0, mmu_idx)) {
+ vaddr page_offset = addr & (TARGET_PAGE_SIZE - 1);
find_qemu_subpage(&addr, &phys_addr, page_size);
+ phys_addr += hexagon_cpu_mmu_enabled(env) ? page_offset : 0;
return phys_addr;
}
--
2.37.2
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [PATCH 02/14] target/hexagon: fix PC advancement for non-COF TB terminators
2026-07-13 20:07 [PATCH 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
2026-07-13 20:07 ` [PATCH 01/14] target/hexagon: fix get_phys_addr_debug with in-page offset Matheus Tavares Bernardino
@ 2026-07-13 20:07 ` Matheus Tavares Bernardino
2026-07-13 21:53 ` Pierrick Bouvier
2026-07-13 20:07 ` [PATCH 03/14] target/hexagon: add aux functions for guest mem load/store Matheus Tavares Bernardino
` (12 subsequent siblings)
14 siblings, 1 reply; 37+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-13 20:07 UTC (permalink / raw)
To: qemu-devel; +Cc: brian.cain, pierrick.bouvier, marco.liebel, philmd, ale, anjo
Some packets end a translation block without a change-of-flow. These do
not update the PC during commit, so gen_end_tb() leaves
hex_gpr[HEX_REG_PC] pointing at the same packet and the block gets
re-entered forever. Set PC explicitly to next_PC in that gen_end_tb()
branch to fix execution of next blocks.
Note that gen_start_packet() used to have a special case for
tlblock/k0lock, setting ctx->next_PC to the packet's own address. This
relies on the tlblock/k0lock helpers to properly advance the PC, which
is never done (only env->next_PC is updated, but that never reaches
hex_gpr[HEX_REG_PC]). Drop the special case so these packets advance to
the following packet like any other non-COF TB terminator.
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 77235916f4b..06e76a6ba34 100644
--- a/target/hexagon/translate.c
+++ b/target/hexagon/translate.c
@@ -210,6 +210,12 @@ static void gen_end_tb(DisasContext *ctx)
gen_goto_tb(ctx, 0, ctx->base.tb->pc, true);
gen_set_label(skip);
gen_goto_tb(ctx, 1, ctx->next_PC, false);
+ } else if (!ctx->pkt.pkt_has_cof) {
+ /*
+ * Packet with no deferred COF that still ends the TB. PC is
+ * not updated during commit, so set it explicitly to next_PC.
+ */
+ gen_goto_tb(ctx, 0, ctx->next_PC, true);
} else {
tcg_gen_lookup_and_goto_ptr();
}
@@ -282,6 +288,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++) {
@@ -291,6 +298,7 @@ static bool check_for_opcode(Packet *pkt, uint16_t opcode)
}
return false;
}
+#endif
static bool need_slot_cancelled(Packet *pkt)
{
@@ -562,10 +570,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] 37+ messages in thread
* [PATCH 03/14] target/hexagon: add aux functions for guest mem load/store
2026-07-13 20:07 [PATCH 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
2026-07-13 20:07 ` [PATCH 01/14] target/hexagon: fix get_phys_addr_debug with in-page offset Matheus Tavares Bernardino
2026-07-13 20:07 ` [PATCH 02/14] target/hexagon: fix PC advancement for non-COF TB terminators Matheus Tavares Bernardino
@ 2026-07-13 20:07 ` Matheus Tavares Bernardino
2026-07-13 21:58 ` Pierrick Bouvier
2026-07-13 20:07 ` [PATCH 04/14] hexagon: cpu_helper: add reg reading/writing helpers Matheus Tavares Bernardino
` (11 subsequent siblings)
14 siblings, 1 reply; 37+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-13 20:07 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, pierrick.bouvier, marco.liebel, philmd, ale, anjo,
Matheus Tavares Bernardino
From: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
Will be used for semihosting.
Signed-off-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/cpu_helper.h | 6 ++
target/hexagon/cpu_helper.c | 133 ++++++++++++++++++++++++++++++++++++
2 files changed, 139 insertions(+)
diff --git a/target/hexagon/cpu_helper.h b/target/hexagon/cpu_helper.h
index d1767503156..f6a31ecbab0 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_touch_memory(CPUHexagonState *env, uint32_t start_addr,
+ uint32_t length, uintptr_t retaddr);
uint32_t hexagon_get_pmu_counter(CPUHexagonState *cur_env, int index);
void hexagon_modify_ssr(CPUHexagonState *env, uint32_t new, uint32_t old);
int get_cpu_mode(CPUHexagonState *env);
diff --git a/target/hexagon/cpu_helper.c b/target/hexagon/cpu_helper.c
index 64c5746c6d9..1ab2564e3dc 100644
--- a/target/hexagon/cpu_helper.c
+++ b/target/hexagon/cpu_helper.c
@@ -25,6 +25,139 @@
#include "sys_macros.h"
#include "arch.h"
+#ifndef CONFIG_USER_ONLY
+
+static bool hexagon_read_memory_small(CPUHexagonState *env, target_ulong addr,
+ int byte_count, unsigned char *dstbuf,
+ int mmu_idx, uintptr_t retaddr)
+ {
+ /* handle small sizes */
+ switch (byte_count) {
+ case 1:
+ *dstbuf = cpu_ldub_mmuidx_ra(env, addr, mmu_idx, retaddr);
+ return true;
+
+ case 2:
+ if (QEMU_IS_ALIGNED(addr, 2)) {
+ *(unsigned short *)dstbuf =
+ cpu_lduw_le_mmuidx_ra(env, addr, mmu_idx, retaddr);
+ return true;
+ }
+ break;
+
+ case 4:
+ if (QEMU_IS_ALIGNED(addr, 4)) {
+ *(uint32_t *)dstbuf =
+ cpu_ldl_le_mmuidx_ra(env, addr, mmu_idx, retaddr);
+ return true;
+ }
+ break;
+
+ case 8:
+ if (QEMU_IS_ALIGNED(addr, 8)) {
+ *(uint64_t *)dstbuf =
+ cpu_ldq_le_mmuidx_ra(env, addr, mmu_idx, retaddr);
+ return true;
+ }
+ break;
+
+ default:
+ /* larger request, handle elsewhere */
+ return false;
+ }
+
+ /* not aligned, copy bytes */
+ for (int i = 0; i < byte_count; ++i) {
+ *dstbuf++ = cpu_ldub_mmuidx_ra(env, addr++, mmu_idx, retaddr);
+ }
+ return true;
+}
+
+void hexagon_read_memory(CPUHexagonState *env, target_ulong vaddr, int size,
+ void *retptr, uintptr_t retaddr)
+{
+ BQL_LOCK_GUARD();
+ CPUState *cs = env_cpu(env);
+ unsigned mmu_idx = cpu_mmu_index(cs, false);
+ if (!hexagon_read_memory_small(env, vaddr, size, retptr, mmu_idx,
+ retaddr)) {
+ cpu_abort(cs, "%s: ERROR: bad size = %d!\n", __func__, size);
+ }
+}
+
+static bool hexagon_write_memory_small(CPUHexagonState *env, target_ulong addr,
+ int byte_count, unsigned char *srcbuf,
+ int mmu_idx, uintptr_t retaddr)
+{
+ /* handle small sizes */
+ switch (byte_count) {
+ case 1:
+ cpu_stb_mmuidx_ra(env, addr, *srcbuf, mmu_idx, retaddr);
+ return true;
+
+ case 2:
+ if (QEMU_IS_ALIGNED(addr, 2)) {
+ cpu_stw_le_mmuidx_ra(env, addr, *(uint16_t *)srcbuf, mmu_idx, retaddr);
+ return true;
+ }
+ break;
+
+ case 4:
+ if (QEMU_IS_ALIGNED(addr, 4)) {
+ cpu_stl_le_mmuidx_ra(env, addr, *(uint32_t *)srcbuf, mmu_idx, retaddr);
+ return true;
+ }
+ break;
+
+ case 8:
+ if (QEMU_IS_ALIGNED(addr, 8)) {
+ cpu_stq_le_mmuidx_ra(env, addr, *(uint64_t *)srcbuf, mmu_idx, retaddr);
+ return true;
+ }
+ break;
+
+ default:
+ /* larger request, handle elsewhere */
+ return false;
+ }
+
+ /* not aligned, copy bytes */
+ for (int i = 0; i < byte_count; ++i) {
+ cpu_stb_mmuidx_ra(env, addr++, *srcbuf++, mmu_idx, retaddr);
+ }
+
+ return true;
+}
+
+void hexagon_write_memory(CPUHexagonState *env, target_ulong vaddr,
+ int size, uint64_t data, uintptr_t retaddr)
+{
+ CPUState *cs = env_cpu(env);
+ unsigned mmu_idx = cpu_mmu_index(cs, false);
+ if (!hexagon_write_memory_small(env, vaddr, size, (unsigned char *)&data,
+ mmu_idx, retaddr)) {
+ cpu_abort(cs, "%s: ERROR: bad size = %d!\n", __func__, size);
+ }
+}
+
+static inline uint32_t page_start(uint32_t addr)
+{
+ uint32_t page_align = ~(TARGET_PAGE_SIZE - 1);
+ return addr & page_align;
+}
+
+void hexagon_touch_memory(CPUHexagonState *env, uint32_t start_addr,
+ uint32_t length, uintptr_t retaddr)
+{
+ unsigned int warm;
+ uint32_t first = page_start(start_addr);
+ uint32_t last = page_start(start_addr + length - 1);
+ for (uint32_t page = first; page <= last; page += TARGET_PAGE_SIZE) {
+ hexagon_read_memory(env, page, 1, &warm, retaddr);
+ }
+}
+
+#endif
uint32_t hexagon_get_pmu_counter(CPUHexagonState *cur_env, int index)
{
--
2.37.2
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [PATCH 04/14] hexagon: cpu_helper: add reg reading/writing helpers
2026-07-13 20:07 [PATCH 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
` (2 preceding siblings ...)
2026-07-13 20:07 ` [PATCH 03/14] target/hexagon: add aux functions for guest mem load/store Matheus Tavares Bernardino
@ 2026-07-13 20:07 ` Matheus Tavares Bernardino
2026-07-13 22:00 ` Pierrick Bouvier
2026-07-13 20:07 ` [PATCH 05/14] semihosting: add callback to set error Matheus Tavares Bernardino
` (10 subsequent siblings)
14 siblings, 1 reply; 37+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-13 20:07 UTC (permalink / raw)
To: qemu-devel; +Cc: brian.cain, pierrick.bouvier, marco.liebel, philmd, ale, anjo
And adjust op_helper to use those. They will also be used on upcoming
semihosting commits.
Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
---
target/hexagon/cpu_helper.h | 18 +++++++++++++++++
target/hexagon/cpu_helper.c | 40 +++++++++++++++++++++++++++++++++++++
target/hexagon/op_helper.c | 18 ++---------------
3 files changed, 60 insertions(+), 16 deletions(-)
diff --git a/target/hexagon/cpu_helper.h b/target/hexagon/cpu_helper.h
index f6a31ecbab0..af286dbe05a 100644
--- a/target/hexagon/cpu_helper.h
+++ b/target/hexagon/cpu_helper.h
@@ -7,6 +7,24 @@
#ifndef HEXAGON_CPU_HELPER_H
#define HEXAGON_CPU_HELPER_H
+static inline void arch_set_thread_reg(CPUHexagonState *env, uint32_t reg,
+ uint32_t val)
+{
+ g_assert(reg < TOTAL_PER_THREAD_REGS);
+ env->gpr[reg] = val;
+}
+
+static inline uint32_t arch_get_thread_reg(CPUHexagonState *env, uint32_t reg)
+{
+ g_assert(reg < TOTAL_PER_THREAD_REGS);
+ return env->gpr[reg];
+}
+
+void arch_set_system_reg(CPUHexagonState *env, uint32_t reg, uint32_t val);
+void arch_set_system_reg_masked(CPUHexagonState *env, uint32_t reg,
+ uint32_t val);
+uint32_t arch_get_system_reg(CPUHexagonState *env, uint32_t reg);
+
void hexagon_read_memory(CPUHexagonState *env, target_ulong vaddr, int size,
void *retptr, uintptr_t retaddr);
void hexagon_write_memory(CPUHexagonState *env, target_ulong vaddr,
diff --git a/target/hexagon/cpu_helper.c b/target/hexagon/cpu_helper.c
index 1ab2564e3dc..ead0cf9d7ca 100644
--- a/target/hexagon/cpu_helper.c
+++ b/target/hexagon/cpu_helper.c
@@ -27,6 +27,46 @@
#ifndef CONFIG_USER_ONLY
+uint32_t arch_get_system_reg(CPUHexagonState *env, uint32_t reg)
+{
+ if (reg == HEX_SREG_PCYCLELO) {
+ return hexagon_get_sys_pcycle_count_low(env);
+ } else if (reg == HEX_SREG_PCYCLEHI) {
+ return hexagon_get_sys_pcycle_count_high(env);
+ }
+
+ g_assert(reg < NUM_SREGS);
+ if (reg < HEX_SREG_GLB_START) {
+ return env->t_sreg[reg];
+ } else {
+ HexagonCPU *cpu = env_archcpu(env);
+ return hexagon_globalreg_read(cpu->globalregs, reg, env->threadId);
+ }
+}
+
+void arch_set_system_reg(CPUHexagonState *env, uint32_t reg, uint32_t val)
+{
+ g_assert(reg < NUM_SREGS);
+ if (reg < HEX_SREG_GLB_START) {
+ env->t_sreg[reg] = val;
+ } else {
+ HexagonCPU *cpu = env_archcpu(env);
+ hexagon_globalreg_write(cpu->globalregs, reg, val, env->threadId);
+ }
+}
+
+void arch_set_system_reg_masked(CPUHexagonState *env, uint32_t reg,
+ uint32_t val)
+{
+ g_assert(reg < NUM_SREGS);
+ if (reg < HEX_SREG_GLB_START) {
+ env->t_sreg[reg] = val;
+ } else {
+ HexagonCPU *cpu = env_archcpu(env);
+ hexagon_globalreg_write_masked(cpu->globalregs, reg, val);
+ }
+}
+
static bool hexagon_read_memory_small(CPUHexagonState *env, target_ulong addr,
int byte_count, unsigned char *dstbuf,
int mmu_idx, uintptr_t retaddr)
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index 125952aee59..4859d8a484e 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -1839,28 +1839,14 @@ void HELPER(setimask)(CPUHexagonState *env, uint32_t tid, uint32_t imask)
void HELPER(sreg_write_masked)(CPUHexagonState *env, uint32_t reg, uint32_t val)
{
BQL_LOCK_GUARD();
- if (reg < HEX_SREG_GLB_START) {
- env->t_sreg[reg] = val;
- } else {
- HexagonCPU *cpu = env_archcpu(env);
- if (cpu->globalregs) {
- hexagon_globalreg_write_masked(cpu->globalregs, reg, val);
- }
- }
+ arch_set_system_reg_masked(env, reg, val);
}
static inline QEMU_ALWAYS_INLINE uint32_t sreg_read(CPUHexagonState *env,
uint32_t reg)
{
- HexagonCPU *cpu;
-
g_assert(bql_locked());
- if (reg < HEX_SREG_GLB_START) {
- return env->t_sreg[reg];
- }
- cpu = env_archcpu(env);
- return cpu->globalregs ?
- hexagon_globalreg_read(cpu->globalregs, reg, env->threadId) : 0;
+ return arch_get_system_reg(env, reg);
}
uint32_t HELPER(sreg_read)(CPUHexagonState *env, uint32_t reg)
--
2.37.2
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [PATCH 05/14] semihosting: add callback to set error
2026-07-13 20:07 [PATCH 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
` (3 preceding siblings ...)
2026-07-13 20:07 ` [PATCH 04/14] hexagon: cpu_helper: add reg reading/writing helpers Matheus Tavares Bernardino
@ 2026-07-13 20:07 ` Matheus Tavares Bernardino
2026-07-13 22:01 ` Pierrick Bouvier
2026-07-14 9:50 ` Daniel Henrique Barboza
2026-07-13 20:07 ` [PATCH 06/14] semihosting: add APIs for chardev-aware guest fd routing Matheus Tavares Bernardino
` (9 subsequent siblings)
14 siblings, 2 replies; 37+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-13 20:07 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, pierrick.bouvier, marco.liebel, philmd, ale, anjo,
Alex Bennée, Peter Maydell, Palmer Dabbelt, Alistair Francis,
Weiwei Li, Daniel Henrique Barboza, Liu Zhiwei, Chao Liu,
qemu-arm, qemu-riscv
This is currently unused by existing semihosting targets, but it will be
used by hexagon.
Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
include/semihosting/common-semi.h | 1 +
semihosting/arm-compat-semi.c | 1 +
target/arm/common-semi-target.c | 4 ++++
target/riscv/common-semi-target.c | 4 ++++
4 files changed, 10 insertions(+)
diff --git a/include/semihosting/common-semi.h b/include/semihosting/common-semi.h
index aa511a46f42..a11905ef4ef 100644
--- a/include/semihosting/common-semi.h
+++ b/include/semihosting/common-semi.h
@@ -37,6 +37,7 @@
void do_common_semihosting(CPUState *cs);
uint64_t common_semi_arg(CPUState *cs, int argno);
void common_semi_set_ret(CPUState *cs, uint64_t ret);
+void common_semi_set_err(CPUState *cs, int err);
bool is_64bit_semihosting(CPUArchState *env);
bool common_semi_sys_exit_is_extended(CPUState *cs);
uint64_t common_semi_stack_bottom(CPUState *cs);
diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index 5e5f181b908..c54753f696f 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -237,6 +237,7 @@ static void common_semi_cb(CPUState *cs, uint64_t ret, int err)
ts->swi_errno = err;
#else
syscall_err = err;
+ common_semi_set_err(cs, err);
#endif
}
common_semi_set_ret(cs, ret);
diff --git a/target/arm/common-semi-target.c b/target/arm/common-semi-target.c
index 2b77ce9c17b..38d52deb3d6 100644
--- a/target/arm/common-semi-target.c
+++ b/target/arm/common-semi-target.c
@@ -34,6 +34,10 @@ void common_semi_set_ret(CPUState *cs, uint64_t ret)
}
}
+void common_semi_set_err(CPUState *cs, int err)
+{
+}
+
bool common_semi_sys_exit_is_extended(CPUState *cs)
{
return is_a64(cpu_env(cs));
diff --git a/target/riscv/common-semi-target.c b/target/riscv/common-semi-target.c
index aeaeb88d536..38a00e160c3 100644
--- a/target/riscv/common-semi-target.c
+++ b/target/riscv/common-semi-target.c
@@ -26,6 +26,10 @@ void common_semi_set_ret(CPUState *cs, uint64_t ret)
env->gpr[xA0] = ret;
}
+void common_semi_set_err(CPUState *cs, int err)
+{
+}
+
bool is_64bit_semihosting(CPUArchState *env)
{
return riscv_cpu_mxl(env) != MXL_RV32;
--
2.37.2
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [PATCH 06/14] semihosting: add APIs for chardev-aware guest fd routing
2026-07-13 20:07 [PATCH 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
` (4 preceding siblings ...)
2026-07-13 20:07 ` [PATCH 05/14] semihosting: add callback to set error Matheus Tavares Bernardino
@ 2026-07-13 20:07 ` Matheus Tavares Bernardino
2026-07-13 22:04 ` Pierrick Bouvier
2026-07-13 20:07 ` [PATCH 07/14] target/hexagon: add semihosting support Matheus Tavares Bernardino
` (8 subsequent siblings)
14 siblings, 1 reply; 37+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-13 20:07 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, pierrick.bouvier, marco.liebel, philmd, ale, anjo,
Alex Bennée
From: Brian Cain <brian.cain@oss.qualcomm.com>
Add qemu_semihosting_console_has_chardev() to query whether the
semihosting console is backed by a chardev, and console_guestfd()
to initialize a guest file descriptor as GuestFDConsole.
These APIs enable callers to route semihosting I/O through a chardev
rather than directly to host stdio.
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
include/semihosting/console.h | 9 +++++++++
include/semihosting/guestfd.h | 9 +++++++++
semihosting/console.c | 5 +++++
semihosting/guestfd.c | 8 ++++++++
4 files changed, 31 insertions(+)
diff --git a/include/semihosting/console.h b/include/semihosting/console.h
index 1c12e178ee3..d5f149e2088 100644
--- a/include/semihosting/console.h
+++ b/include/semihosting/console.h
@@ -54,4 +54,13 @@ void qemu_semihosting_console_block_until_ready(CPUState *cs);
*/
bool qemu_semihosting_console_ready(void);
+/**
+ * qemu_semihosting_console_has_chardev:
+ *
+ * Return true if the semihosting console is backed by a chardev.
+ * When true, console I/O goes through the chardev rather than
+ * host stdio.
+ */
+bool qemu_semihosting_console_has_chardev(void);
+
#endif /* SEMIHOST_CONSOLE_H */
diff --git a/include/semihosting/guestfd.h b/include/semihosting/guestfd.h
index a7ea1041ea0..76ca0fcf1a7 100644
--- a/include/semihosting/guestfd.h
+++ b/include/semihosting/guestfd.h
@@ -70,6 +70,15 @@ GuestFD *get_guestfd(int guestfd);
*/
void associate_guestfd(int guestfd, int hostfd);
+/**
+ * console_guestfd:
+ * @guestfd: GuestFD index
+ *
+ * Initialize the GuestFD for @guestfd to GuestFDConsole.
+ * I/O will be routed through the semihosting console chardev.
+ */
+void console_guestfd(int guestfd);
+
/**
* staticfile_guestfd:
* @guestfd: GuestFD index
diff --git a/semihosting/console.c b/semihosting/console.c
index 91e5d50d502..9d786833564 100644
--- a/semihosting/console.c
+++ b/semihosting/console.c
@@ -108,6 +108,11 @@ int qemu_semihosting_console_read(CPUState *cs, void *buf, int len)
return ret;
}
+bool qemu_semihosting_console_has_chardev(void)
+{
+ return console.chr != NULL;
+}
+
int qemu_semihosting_console_write(void *buf, int len)
{
if (console.chr) {
diff --git a/semihosting/guestfd.c b/semihosting/guestfd.c
index e8f236c690c..8b5770bab0d 100644
--- a/semihosting/guestfd.c
+++ b/semihosting/guestfd.c
@@ -117,6 +117,14 @@ void associate_guestfd(int guestfd, int hostfd)
gf->hostfd = hostfd;
}
+void console_guestfd(int guestfd)
+{
+ GuestFD *gf = do_get_guestfd(guestfd);
+
+ assert(gf);
+ gf->type = GuestFDConsole;
+}
+
void staticfile_guestfd(int guestfd, const uint8_t *data, size_t len)
{
GuestFD *gf = do_get_guestfd(guestfd);
--
2.37.2
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [PATCH 07/14] target/hexagon: add semihosting support
2026-07-13 20:07 [PATCH 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
` (5 preceding siblings ...)
2026-07-13 20:07 ` [PATCH 06/14] semihosting: add APIs for chardev-aware guest fd routing Matheus Tavares Bernardino
@ 2026-07-13 20:07 ` Matheus Tavares Bernardino
2026-07-13 22:11 ` Pierrick Bouvier
2026-07-13 20:07 ` [PATCH 08/14] semihosting: add ftruncate helper (to be used for hexagon) Matheus Tavares Bernardino
` (7 subsequent siblings)
14 siblings, 1 reply; 37+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-13 20:07 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, pierrick.bouvier, marco.liebel, philmd, ale, anjo,
Matheus Tavares Bernardino, Paolo Bonzini
From: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
Baremetal Hexagon programs use trap0 #0 to invoke
semihosting calls for I/O and process control. Wire up the
arm-compatible semihosting framework for softmmu by enabling
CONFIG_ARM_COMPATIBLE_SEMIHOSTING and routing trap0 to the
semihosting handler.
Signed-off-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
configs/targets/hexagon-softmmu.mak | 2 +
hw/hexagon/hexagon_dsp.c | 2 +
target/hexagon/common-semi-target.c | 51 +++++++++
target/hexagon/hexswi.c | 164 +++++++++++++++++++++++++++-
hw/hexagon/Kconfig | 1 +
qemu-options.hx | 8 +-
target/hexagon/meson.build | 3 +
7 files changed, 224 insertions(+), 7 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 a77c100f0c5..6cbdc64be56 100644
--- a/configs/targets/hexagon-softmmu.mak
+++ b/configs/targets/hexagon-softmmu.mak
@@ -6,3 +6,5 @@ TARGET_LONG_BITS=32
TARGET_NOT_USING_LEGACY_LDST_PHYS_API=y
TARGET_NOT_USING_LEGACY_NATIVE_ENDIAN_API=y
TARGET_NEED_FDT=y
+CONFIG_SEMIHOSTING=y
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
diff --git a/hw/hexagon/hexagon_dsp.c b/hw/hexagon/hexagon_dsp.c
index aa493993229..315733cded3 100644
--- a/hw/hexagon/hexagon_dsp.c
+++ b/hw/hexagon/hexagon_dsp.c
@@ -27,6 +27,7 @@
#include "target/hexagon/internal.h"
#include "system/physmem.h"
#include "system/reset.h"
+#include "semihosting/semihost.h"
#include "machine_cfg_v66g_1024.h.inc"
@@ -178,6 +179,7 @@ static void init_mc(MachineClass *mc)
mc->no_serial = 1;
mc->is_default = false;
mc->max_cpus = 8;
+ qemu_semihosting_enable();
}
/* ----------------------------------------------------------------- */
diff --git a/target/hexagon/common-semi-target.c b/target/hexagon/common-semi-target.c
new file mode 100644
index 00000000000..9a7720514bb
--- /dev/null
+++ b/target/hexagon/common-semi-target.c
@@ -0,0 +1,51 @@
+/*
+ * Target-specific parts of semihosting/arm-compat-semi.c.
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "cpu_helper.h"
+#include "semihosting/common-semi.h"
+
+uint64_t common_semi_arg(CPUState *cs, int argno)
+{
+ CPUHexagonState *env = cpu_env(cs);
+ return arch_get_thread_reg(env, HEX_REG_R00 + argno);
+}
+
+void common_semi_set_ret(CPUState *cs, uint64_t ret)
+{
+ CPUHexagonState *env = cpu_env(cs);
+ arch_set_thread_reg(env, HEX_REG_R00, ret);
+}
+
+void common_semi_set_err(CPUState *cs, int err)
+{
+ CPUHexagonState *env = cpu_env(cs);
+ arch_set_thread_reg(env, HEX_REG_R01, err);
+}
+
+bool common_semi_sys_exit_is_extended(CPUState *cs)
+{
+ return false;
+}
+
+bool is_64bit_semihosting(CPUArchState *env)
+{
+ return false;
+}
+
+uint64_t common_semi_stack_bottom(CPUState *cs)
+{
+ CPUHexagonState *env = cpu_env(cs);
+ return arch_get_thread_reg(env, HEX_REG_SP);
+}
+
+bool common_semi_has_synccache(CPUArchState *env)
+{
+ return false;
+}
diff --git a/target/hexagon/hexswi.c b/target/hexagon/hexswi.c
index 43c373ea2ee..ce9c85ad6aa 100644
--- a/target/hexagon/hexswi.c
+++ b/target/hexagon/hexswi.c
@@ -24,9 +24,168 @@
#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_touch_memory(env, addr, count, retaddr);
+}
+
+static void sim_handle_trap0(CPUHexagonState *env)
+{
+ target_ulong what_swi, swi_info;
+ G_GNUC_UNUSED uintptr_t retaddr = 0;
+ CPUState *cs = env_cpu(env);
+
+ g_assert(bql_locked());
+ init_semihosting_guestfds();
+
+ what_swi = arch_get_thread_reg(env, HEX_REG_R00);
+ swi_info = arch_get_thread_reg(env, HEX_REG_R01);
+
+ qemu_log_mask(CPU_LOG_INT,
+ "sim_handle_trap0: swi=0x%" PRIx32
+ " info=0x%" PRIx32 " PC=0x%" PRIx32
+ " thread=%" PRId32 "\n",
+ (uint32_t)what_swi, (uint32_t)swi_info,
+ (uint32_t)arch_get_thread_reg(env, HEX_REG_PC),
+ (uint32_t)env->threadId);
+
+ if (!is_hexagon_specific_swi_flag(what_swi)) {
+ if (what_swi == HEX_SYS_READ || what_swi == HEX_SYS_READC ||
+ what_swi == HEX_SYS_WRITE) {
+ /*
+ * Avoid page faults if the buffer is not in memory yet.
+ * NOTE: Counterintuitive, but a WRITE must be able to LOAD from
+ * the input address. The contents of that buffer will be
+ * directed to the SWI interface.
+ */
+ do_preload(env, swi_info, (what_swi == HEX_SYS_WRITE));
+ }
+ /*
+ * ARM-compat semihosting SWI numbers are all <= 0x31.
+ * If R0 holds a value outside that range (e.g. guest code
+ * executing trap0(#0) with an arbitrary R0), treat it as an
+ * unrecognized request rather than forwarding to
+ * do_common_semihosting() which would abort.
+ */
+ if (what_swi > 0x31) {
+ qemu_log_mask(LOG_UNIMP,
+ "trap0(#0): unrecognized request in r0: "
+ "0x" TARGET_FMT_lx "\n", what_swi);
+ return;
+ }
+ do_common_semihosting(cs);
+ return;
+ }
+
+ switch (what_swi) {
+
+ case HEX_SYS_EXCEPTION:
+ arch_set_system_reg(env, HEX_SREG_MODECTL, 0);
+ qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
+ break;
+
+ /* TODO: implement other hexagon-specific semihosting calls */
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "unknown swi request: 0x%" PRIx32 "\n",
+ (uint32_t)what_swi);
+ common_semi_cb(cs, -1, ENOSYS);
+ }
+}
+
static void set_addresses(CPUHexagonState *env, uint32_t pc_offset,
uint32_t exception_index)
-
{
HexagonCPU *cpu = env_archcpu(env);
uint32_t evb = cpu->globalregs ?
@@ -95,8 +254,7 @@ void hexagon_cpu_do_interrupt(CPUState *cs)
switch (cs->exception_index) {
case HEX_EVENT_TRAP0:
if (env->cause_code == 0) {
- qemu_log_mask(LOG_UNIMP,
- "trap0 is unhandled, no semihosting available\n");
+ sim_handle_trap0(env);
}
hexagon_ssr_set_cause(env, env->cause_code);
diff --git a/hw/hexagon/Kconfig b/hw/hexagon/Kconfig
index 52065ab3b22..3a8ff17812b 100644
--- a/hw/hexagon/Kconfig
+++ b/hw/hexagon/Kconfig
@@ -2,6 +2,7 @@ config HEX_DSP
bool
default y
depends on HEXAGON
+ select ARM_COMPATIBLE_SEMIHOSTING
config HEX_VIRT
bool
diff --git a/qemu-options.hx b/qemu-options.hx
index 34970fffc94..56f42b02c8a 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -5507,7 +5507,7 @@ ERST
DEF("semihosting", 0, QEMU_OPTION_semihosting,
"-semihosting semihosting mode\n",
QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA |
- QEMU_ARCH_MIPS | QEMU_ARCH_RISCV)
+ QEMU_ARCH_MIPS | QEMU_ARCH_RISCV | QEMU_ARCH_HEXAGON)
SRST
``-semihosting``
Enable :ref:`Semihosting` mode (ARM, M68K, Xtensa, MIPS, RISC-V only).
@@ -5523,11 +5523,11 @@ DEF("semihosting-config", HAS_ARG, QEMU_OPTION_semihosting_config,
"-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,userspace=on|off][,arg=str[,...]]\n" \
" semihosting configuration\n",
QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA |
-QEMU_ARCH_MIPS | QEMU_ARCH_RISCV)
+QEMU_ARCH_MIPS | QEMU_ARCH_RISCV | QEMU_ARCH_HEXAGON)
SRST
``-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,userspace=on|off][,arg=str[,...]]``
- Enable and configure :ref:`Semihosting` (ARM, M68K, Xtensa, MIPS, RISC-V
- only).
+ Enable and configure :ref:`Semihosting` (ARM, M68K, Xtensa, MIPS, RISC-V,
+ Hexagon only).
.. warning::
Note that this allows guest direct access to the host filesystem, so
diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
index 59cb09c1070..69f01bd2f70 100644
--- a/target/hexagon/meson.build
+++ b/target/hexagon/meson.build
@@ -262,6 +262,9 @@ hexagon_softmmu_ss.add(files(
'machine.c',
))
+hexagon_softmmu_ss.add(when: 'CONFIG_ARM_COMPATIBLE_SEMIHOSTING',
+ if_true: files('common-semi-target.c'))
+
#
# Step 4.5
# We use flex/bison based idef-parser to generate TCG code for a lot
--
2.37.2
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [PATCH 08/14] semihosting: add ftruncate helper (to be used for hexagon)
2026-07-13 20:07 [PATCH 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
` (6 preceding siblings ...)
2026-07-13 20:07 ` [PATCH 07/14] target/hexagon: add semihosting support Matheus Tavares Bernardino
@ 2026-07-13 20:07 ` Matheus Tavares Bernardino
2026-07-13 22:12 ` Pierrick Bouvier
2026-07-13 20:07 ` [PATCH 09/14] target/hexagon: add main arch-specific semihosting operations Matheus Tavares Bernardino
` (6 subsequent siblings)
14 siblings, 1 reply; 37+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-13 20:07 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, pierrick.bouvier, marco.liebel, philmd, ale, anjo,
Alex Bennée
The common semihosting syscall layer has no ftruncate
helper, but the Hexagon semihosting ABI includes an FTRUNC
operation. Add semihost_sys_ftruncate() so that Hexagon
can delegate to it rather than calling ftruncate directly.
Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
include/semihosting/syscalls.h | 2 ++
semihosting/syscalls.c | 29 +++++++++++++++++++++++++++++
2 files changed, 31 insertions(+)
diff --git a/include/semihosting/syscalls.h b/include/semihosting/syscalls.h
index 03aa45b7bb9..3919ab64c7c 100644
--- a/include/semihosting/syscalls.h
+++ b/include/semihosting/syscalls.h
@@ -75,4 +75,6 @@ void semihost_sys_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete,
void semihost_sys_poll_one(CPUState *cs, gdb_syscall_complete_cb complete,
int fd, GIOCondition cond, int timeout);
+void semihost_sys_ftruncate(CPUState *cs, gdb_syscall_complete_cb complete,
+ int fd, off_t len);
#endif /* SEMIHOSTING_SYSCALLS_H */
diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c
index 20f155f869a..0456db0befb 100644
--- a/semihosting/syscalls.c
+++ b/semihosting/syscalls.c
@@ -8,10 +8,12 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
+#include "qemu/error-report.h"
#include "gdbstub/syscalls.h"
#include "semihosting/guestfd.h"
#include "semihosting/syscalls.h"
#include "semihosting/console.h"
+#include "semihosting/semihost.h"
#ifdef CONFIG_USER_ONLY
#include "qemu.h"
#else
@@ -541,6 +543,13 @@ static void host_poll_one(CPUState *cs, gdb_syscall_complete_cb complete,
}
#endif
+static void host_ftruncate(CPUState *cs, gdb_syscall_complete_cb complete,
+ GuestFD *gf, off_t len)
+{
+ int err = ftruncate(gf->hostfd, len);
+ complete(cs, err, err < 0 ? errno : 0);
+}
+
/*
* Static file semihosting syscall implementations.
*/
@@ -982,3 +991,23 @@ void semihost_sys_poll_one(CPUState *cs, gdb_syscall_complete_cb complete,
}
}
#endif
+
+void semihost_sys_ftruncate(CPUState *cs, gdb_syscall_complete_cb complete,
+ int fd, off_t len)
+{
+ GuestFD *gf = get_guestfd(fd);
+ if (!gf) {
+ complete(cs, -1, EBADF);
+ return;
+ }
+
+ switch (gf->type) {
+ case GuestFDHost:
+ host_ftruncate(cs, complete, gf, len);
+ break;
+ default:
+ error_report("ftruncate call not implemented "
+ "for this semihosting mode.");
+ g_assert_not_reached();
+ }
+}
--
2.37.2
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [PATCH 09/14] target/hexagon: add main arch-specific semihosting operations
2026-07-13 20:07 [PATCH 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
` (7 preceding siblings ...)
2026-07-13 20:07 ` [PATCH 08/14] semihosting: add ftruncate helper (to be used for hexagon) Matheus Tavares Bernardino
@ 2026-07-13 20:07 ` Matheus Tavares Bernardino
2026-07-13 22:20 ` Pierrick Bouvier
2026-07-13 20:07 ` [PATCH 10/14] target/hexagon: add COREDUMP semihosting operation Matheus Tavares Bernardino
` (5 subsequent siblings)
14 siblings, 1 reply; 37+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-13 20:07 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, pierrick.bouvier, marco.liebel, philmd, ale, anjo,
Alex Bennée
The Hexagon semihosting ABI extends the arm-compatible set with
operations like OPEN, WRITECREG, WRITE0, ISTTY, STAT, FSTAT, FTELL,
SEEK, FTRUNC, ACCESS, and GETCWD. Implement these trap0 handlers so
that baremetal programs using the standard Hexagon simulator ABI can
perform file I/O when running on qemu-system-hexagon.
Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
include/semihosting/common-semi.h | 1 +
semihosting/arm-compat-semi.c | 2 +-
target/hexagon/hexswi.c | 293 +++++++++++++++++++++++++++++-
3 files changed, 294 insertions(+), 2 deletions(-)
diff --git a/include/semihosting/common-semi.h b/include/semihosting/common-semi.h
index a11905ef4ef..1e7699d7bbd 100644
--- a/include/semihosting/common-semi.h
+++ b/include/semihosting/common-semi.h
@@ -34,6 +34,7 @@
#ifndef COMMON_SEMI_H
#define COMMON_SEMI_H
+void common_semi_cb(CPUState *cs, uint64_t ret, int err);
void do_common_semihosting(CPUState *cs);
uint64_t common_semi_arg(CPUState *cs, int argno);
void common_semi_set_ret(CPUState *cs, uint64_t ret);
diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index c54753f696f..b930a028649 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -229,7 +229,7 @@ static inline uint32_t get_swi_errno(CPUState *cs)
#endif
}
-static void common_semi_cb(CPUState *cs, uint64_t ret, int err)
+void common_semi_cb(CPUState *cs, uint64_t ret, int err)
{
if (err) {
#ifdef CONFIG_USER_ONLY
diff --git a/target/hexagon/hexswi.c b/target/hexagon/hexswi.c
index ce9c85ad6aa..2c60e4d9e9f 100644
--- a/target/hexagon/hexswi.c
+++ b/target/hexagon/hexswi.c
@@ -119,6 +119,14 @@ static void do_preload(CPUHexagonState *env, target_ulong swi_info, bool load)
hexagon_touch_memory(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;
@@ -174,7 +182,290 @@ static void sim_handle_trap0(CPUHexagonState *env)
qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
break;
- /* TODO: implement other hexagon-specific semihosting calls */
+#ifndef _WIN32
+ case HEX_SYS_OPEN:
+ {
+ char filename[BUFSIZ];
+ target_ulong physicalFilenameAddr;
+ unsigned int filemode;
+ int length;
+ int real_openmode;
+ int ret, err = 0;
+ int i = 0;
+ static const unsigned int mode_table[] = {
+ O_RDONLY,
+ O_RDONLY | O_BINARY,
+ O_RDWR,
+ O_RDWR | O_BINARY,
+ O_WRONLY | O_CREAT | O_TRUNC,
+ O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
+ O_RDWR | O_CREAT | O_TRUNC,
+ O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
+ O_WRONLY | O_APPEND | O_CREAT,
+ O_WRONLY | O_APPEND | O_CREAT | O_BINARY,
+ O_RDWR | O_APPEND | O_CREAT,
+ O_RDWR | O_APPEND | O_CREAT | O_BINARY,
+ O_RDWR | O_CREAT,
+ O_RDWR | O_CREAT | O_EXCL
+ };
+
+
+ hexagon_read_memory(env, swi_info, 4, &physicalFilenameAddr, retaddr);
+ hexagon_read_memory(env, swi_info + 4, 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, physicalFilenameAddr + i, 1, &filename[i],
+ retaddr);
+ i++;
+ } while (filename[i - 1]);
+
+ /* convert ARM ANGEL filemode into host filemode */
+ if (filemode < 14) {
+ real_openmode = mode_table[filemode];
+ } 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 out 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:
+ {
+ /*
+ * This must match the caller's definition, it would be in the
+ * caller's angel.h or equivalent header.
+ */
+ struct __SYS_STAT {
+ uint64_t dev;
+ uint64_t ino;
+ uint32_t mode;
+ uint32_t nlink;
+ uint64_t rdev;
+ uint32_t size;
+ uint32_t __pad1;
+ uint32_t atime;
+ uint32_t mtime;
+ uint32_t ctime;
+ uint32_t __pad2;
+ } sys_stat;
+ struct stat st_buf;
+ uint8_t *st_bufptr = (uint8_t *)&sys_stat;
+ int rc, err = 0;
+ char filename[BUFSIZ];
+ target_ulong physicalFilenameAddr;
+ target_ulong statBufferAddr;
+ hexagon_read_memory(env, swi_info, 4, &physicalFilenameAddr, retaddr);
+
+ if (what_swi == HEX_SYS_STAT) {
+ int i = 0;
+ do {
+ hexagon_read_memory(env, physicalFilenameAddr + i, 1,
+ &filename[i], retaddr);
+ i++;
+ } while ((i < BUFSIZ) && filename[i - 1]);
+ rc = stat(filename, &st_buf);
+ err = errno;
+ } else {
+ int fd = physicalFilenameAddr;
+ GuestFD *gf = get_guestfd(fd);
+ if (!gf || gf->type != GuestFDHost) {
+ qemu_log_mask(LOG_UNIMP,
+ "fstat semihosting only implemented"
+ " for native mode\n");
+ g_assert_not_reached();
+ }
+ rc = fstat(gf->hostfd, &st_buf);
+ err = errno;
+ }
+ if (rc == 0) {
+ sys_stat.dev = st_buf.st_dev;
+ sys_stat.ino = st_buf.st_ino;
+ sys_stat.mode = st_buf.st_mode;
+ sys_stat.nlink = (uint32_t) st_buf.st_nlink;
+ sys_stat.rdev = st_buf.st_rdev;
+ sys_stat.size = (uint32_t) st_buf.st_size;
+ 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;
+ }
+ hexagon_read_memory(env, swi_info + 4, 4, &statBufferAddr, retaddr);
+
+ for (int i = 0; i < sizeof(sys_stat); i++) {
+ hexagon_write_memory(env, statBufferAddr + i, 1, st_bufptr[i],
+ retaddr);
+ }
+ common_semi_cb(cs, rc, rc == 0 ? 0 : err);
+ }
+ break;
+
+ case HEX_SYS_FTRUNC:
+ {
+ int fd;
+ off_t size_limit;
+ hexagon_read_memory(env, swi_info, 4, &fd, retaddr);
+ hexagon_read_memory(env, swi_info + 4, 8, &size_limit, retaddr);
+ semihost_sys_ftruncate(cs, common_semi_cb, fd, size_limit);
+ }
+ break;
+
+ case HEX_SYS_ACCESS:
+ {
+ char filename[BUFSIZ];
+ uint32_t FileNameAddr;
+ uint32_t BufferMode;
+ int rc;
+
+ int i = 0;
+
+ hexagon_read_memory(env, swi_info, 4, &FileNameAddr, retaddr);
+ do {
+ hexagon_read_memory(env, FileNameAddr + i, 1, &filename[i],
+ retaddr);
+ i++;
+ } while ((i < BUFSIZ) && (filename[i - 1]));
+ filename[i] = 0;
+
+ hexagon_read_memory(env, swi_info + 4, 4, &BufferMode, retaddr);
+
+ rc = access(filename, BufferMode);
+ common_semi_cb(cs, rc, rc == 0 ? 0 : errno);
+ }
+ break;
+
+ case HEX_SYS_GETCWD:
+ {
+ char cwdPtr[PATH_MAX];
+ uint32_t BufferAddr;
+ uint32_t BufferSize;
+ uint32_t rc = 0, err = 0;
+
+ hexagon_read_memory(env, swi_info, 4, &BufferAddr, retaddr);
+ hexagon_read_memory(env, swi_info + 4, 4, &BufferSize, retaddr);
+
+ if (!getcwd(cwdPtr, PATH_MAX)) {
+ err = errno;
+ } else {
+ size_t cwd_size = strlen(cwdPtr);
+ if (cwd_size > BufferSize) {
+ err = ERANGE;
+ } else {
+ for (int i = 0; i < cwd_size; i++) {
+ hexagon_write_memory(env, BufferAddr + i, 1,
+ (uint64_t)cwdPtr[i], retaddr);
+ }
+ rc = BufferAddr;
+ }
+ }
+ common_semi_cb(cs, rc, rc != 0 ? 0 : err);
+ break;
+ }
+
+ case HEX_SYS_EXEC:
+ {
+ qemu_log_mask(LOG_UNIMP, "SYS_EXEC is deprecated\n");
+ common_semi_cb(cs, -1, ENOSYS);
+ }
+ break;
+
+ case HEX_SYS_FTELL:
+ {
+ int fd;
+ hexagon_read_memory(env, swi_info, 4, &fd, retaddr);
+ semihost_sys_lseek(cs, common_semi_ftell_cb, fd, 0, GDB_SEEK_CUR);
+ }
+ break;
+
+ case HEX_SYS_READ_CYCLES:
+ case HEX_SYS_READ_TCYCLES:
+ case HEX_SYS_READ_ICOUNT:
+ {
+ arch_set_thread_reg(env, HEX_REG_R00, 0);
+ arch_set_thread_reg(env, HEX_REG_R01, 0);
+ break;
+ }
+
+ case HEX_SYS_READ_PCYCLES:
+ {
+ arch_set_thread_reg(env, HEX_REG_R00,
+ arch_get_system_reg(env, HEX_SREG_PCYCLELO));
+ arch_set_thread_reg(env, HEX_REG_R01,
+ arch_get_system_reg(env, HEX_SREG_PCYCLEHI));
+ break;
+ }
+
+ case HEX_SYS_PROF_ON:
+ case HEX_SYS_PROF_OFF:
+ case HEX_SYS_PROF_STATSRESET:
+ case HEX_SYS_DUMP_PMU_STATS:
+ case HEX_SYS_HEAPINFO:
+ common_semi_cb(cs, -1, ENOSYS);
+ qemu_log_mask(LOG_UNIMP,
+ "SWI call %" PRIx32
+ " is unimplemented in QEMU\n",
+ (uint32_t)what_swi);
+ break;
+
+#endif /* ! _WIN32 */
default:
qemu_log_mask(LOG_GUEST_ERROR,
--
2.37.2
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [PATCH 10/14] target/hexagon: add COREDUMP semihosting operation
2026-07-13 20:07 [PATCH 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
` (8 preceding siblings ...)
2026-07-13 20:07 ` [PATCH 09/14] target/hexagon: add main arch-specific semihosting operations Matheus Tavares Bernardino
@ 2026-07-13 20:07 ` Matheus Tavares Bernardino
2026-07-13 22:22 ` Pierrick Bouvier
2026-07-13 20:07 ` [PATCH 11/14] target/hexagon: add OPEN/READ/CLOSE_DIR semihosting operations Matheus Tavares Bernardino
` (4 subsequent siblings)
14 siblings, 1 reply; 37+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-13 20:07 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, pierrick.bouvier, marco.liebel, philmd, ale, anjo,
Matheus Tavares Bernardino
From: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
Baremetal Hexagon programs invoke SYS_COREDUMP (0xCD)
through semihosting to dump CPU state on a fatal exception.
Implement the handler to decode the SSR cause field and
print the full register file, matching hexagon-sim behavior.
Signed-off-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/internal.h | 1 +
target/hexagon/cpu.c | 2 +-
target/hexagon/hexswi.c | 143 ++++++++++++++++++++++++++++++++++++++
3 files changed, 145 insertions(+), 1 deletion(-)
diff --git a/target/hexagon/internal.h b/target/hexagon/internal.h
index 00b37aea7af..05d1129916e 100644
--- a/target/hexagon/internal.h
+++ b/target/hexagon/internal.h
@@ -28,6 +28,7 @@ int hexagon_hvx_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n);
void hexagon_debug_vreg(CPUHexagonState *env, int regnum);
void hexagon_debug_qreg(CPUHexagonState *env, int regnum);
void hexagon_debug(CPUHexagonState *env);
+void hexagon_dump(CPUHexagonState *env, FILE *f, int flags);
extern const char * const hexagon_regnames[TOTAL_PER_THREAD_REGS];
#ifndef CONFIG_USER_ONLY
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index 028cfe9edde..8be4097ecdb 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -232,7 +232,7 @@ void hexagon_debug_qreg(CPUHexagonState *env, int regnum)
print_qreg(stdout, env, regnum, false);
}
-static void hexagon_dump(CPUHexagonState *env, FILE *f, int flags)
+void hexagon_dump(CPUHexagonState *env, FILE *f, int flags)
{
HexagonCPU *cpu = env_archcpu(env);
diff --git a/target/hexagon/hexswi.c b/target/hexagon/hexswi.c
index 2c60e4d9e9f..7efd33d3533 100644
--- a/target/hexagon/hexswi.c
+++ b/target/hexagon/hexswi.c
@@ -127,6 +127,145 @@ static void common_semi_ftell_cb(CPUState *cs, uint64_t ret, int err)
common_semi_cb(cs, ret, err);
}
+static void coredump(CPUHexagonState *env)
+{
+ uint32_t ssr = arch_get_system_reg(env, HEX_SREG_SSR);
+ FILE *f = qemu_log_trylock();
+
+ if (!f) {
+ return;
+ }
+
+ fprintf(f, "CRASH!\n");
+ fprintf(f, "I think the exception was: ");
+ switch (GET_SSR_FIELD(SSR_CAUSE, ssr)) {
+ case 0x43:
+ fprintf(f, "0x43, NMI");
+ break;
+ case 0x42:
+ fprintf(f, "0x42, Data abort");
+ break;
+ case 0x44:
+ fprintf(f, "0x44, Multi TLB match");
+ break;
+ case HEX_CAUSE_BIU_PRECISE:
+ fprintf(f, "0x%x, Bus Error (Precise BIU error)",
+ HEX_CAUSE_BIU_PRECISE);
+ break;
+ case HEX_CAUSE_DOUBLE_EXCEPT:
+ fprintf(f, "0x%x, Exception observed when EX = 1"
+ " (double exception)",
+ HEX_CAUSE_DOUBLE_EXCEPT);
+ break;
+ case HEX_CAUSE_FETCH_NO_XPAGE:
+ fprintf(f, "0x%x, Privilege violation: User/Guest mode execute"
+ " to page with no execute permissions",
+ HEX_CAUSE_FETCH_NO_XPAGE);
+ break;
+ case HEX_CAUSE_FETCH_NO_UPAGE:
+ fprintf(f, "0x%x, Privilege violation: "
+ "User mode execute to page with no user permissions",
+ HEX_CAUSE_FETCH_NO_UPAGE);
+ break;
+ case HEX_CAUSE_INVALID_PACKET:
+ fprintf(f, "0x%x, Invalid packet",
+ HEX_CAUSE_INVALID_PACKET);
+ break;
+ case HEX_CAUSE_PRIV_USER_NO_GINSN:
+ fprintf(f, "0x%x, Privilege violation:"
+ " guest mode insn in user mode",
+ HEX_CAUSE_PRIV_USER_NO_GINSN);
+ break;
+ case HEX_CAUSE_PRIV_USER_NO_SINSN:
+ fprintf(f, "0x%x, Privilege violation: "
+ "monitor mode insn in user/guest mode",
+ HEX_CAUSE_PRIV_USER_NO_SINSN);
+ break;
+ case HEX_CAUSE_REG_WRITE_CONFLICT:
+ fprintf(f, "0x%x, Multiple writes to same register",
+ HEX_CAUSE_REG_WRITE_CONFLICT);
+ break;
+ case HEX_CAUSE_PC_NOT_ALIGNED:
+ fprintf(f, "0x%x, PC not aligned",
+ HEX_CAUSE_PC_NOT_ALIGNED);
+ break;
+ case HEX_CAUSE_MISALIGNED_LOAD:
+ fprintf(f, "0x%x, Misaligned Load @ 0x%" PRIx32,
+ HEX_CAUSE_MISALIGNED_LOAD,
+ arch_get_system_reg(env, HEX_SREG_BADVA));
+ break;
+ case HEX_CAUSE_MISALIGNED_STORE:
+ fprintf(f, "0x%x, Misaligned Store @ 0x%" PRIx32,
+ HEX_CAUSE_MISALIGNED_STORE,
+ arch_get_system_reg(env, HEX_SREG_BADVA));
+ break;
+ case HEX_CAUSE_PRIV_NO_READ:
+ fprintf(f, "0x%x, Privilege violation: "
+ "user/guest read permission @ 0x%" PRIx32,
+ HEX_CAUSE_PRIV_NO_READ,
+ arch_get_system_reg(env, HEX_SREG_BADVA));
+ break;
+ case HEX_CAUSE_PRIV_NO_WRITE:
+ fprintf(f, "0x%x, Privilege violation: "
+ "user/guest write permission @ 0x%" PRIx32,
+ HEX_CAUSE_PRIV_NO_WRITE,
+ arch_get_system_reg(env, HEX_SREG_BADVA));
+ break;
+ case HEX_CAUSE_PRIV_NO_UREAD:
+ fprintf(f, "0x%x, Privilege violation:"
+ " user read permission @ 0x%" PRIx32,
+ HEX_CAUSE_PRIV_NO_UREAD,
+ arch_get_system_reg(env, HEX_SREG_BADVA));
+ break;
+ case HEX_CAUSE_PRIV_NO_UWRITE:
+ fprintf(f, "0x%x, Privilege violation:"
+ " user write permission @ 0x%" PRIx32,
+ HEX_CAUSE_PRIV_NO_UWRITE,
+ arch_get_system_reg(env, HEX_SREG_BADVA));
+ break;
+ case HEX_CAUSE_COPROC_LDST:
+ fprintf(f, "0x%x, Coprocessor VMEM address error @ 0x%" PRIx32,
+ HEX_CAUSE_COPROC_LDST,
+ arch_get_system_reg(env, HEX_SREG_BADVA));
+ break;
+ case HEX_CAUSE_STACK_LIMIT:
+ fprintf(f, "0x%x, Stack limit check error",
+ HEX_CAUSE_STACK_LIMIT);
+ break;
+ case HEX_CAUSE_FPTRAP_CAUSE_BADFLOAT:
+ fprintf(f, "0x%x, Floating-Point: Execution of Floating-Point "
+ "instruction resulted in exception",
+ HEX_CAUSE_FPTRAP_CAUSE_BADFLOAT);
+ break;
+ case HEX_CAUSE_NO_COPROC_ENABLE:
+ fprintf(f, "0x%x, Illegal Execution of Coprocessor Instruction",
+ HEX_CAUSE_NO_COPROC_ENABLE);
+ break;
+ case HEX_CAUSE_NO_COPROC2_ENABLE:
+ fprintf(f, "0x%x, Illegal Execution of Secondary"
+ " Coprocessor Instruction",
+ HEX_CAUSE_NO_COPROC2_ENABLE);
+ break;
+ case HEX_CAUSE_UNSUPPORTED_HVX_64B:
+ fprintf(f, "0x%x, Unsupported Execution of"
+ " Coprocessor Instruction with 64bits Mode On",
+ HEX_CAUSE_UNSUPPORTED_HVX_64B);
+ break;
+ case HEX_CAUSE_VWCTRL_WINDOW_MISS:
+ fprintf(f, "0x%x, Thread accessing a region"
+ " outside VWCTRL window",
+ HEX_CAUSE_VWCTRL_WINDOW_MISS);
+ break;
+ default:
+ fprintf(f, "unknown cause 0x%" PRIx32,
+ GET_SSR_FIELD(SSR_CAUSE, ssr));
+ break;
+ }
+ fprintf(f, "\nRegister Dump:\n");
+ hexagon_dump(env, f, 0);
+ qemu_log_unlock(f);
+}
+
static void sim_handle_trap0(CPUHexagonState *env)
{
target_ulong what_swi, swi_info;
@@ -427,6 +566,10 @@ static void sim_handle_trap0(CPUHexagonState *env)
}
break;
+ case HEX_SYS_COREDUMP:
+ coredump(env);
+ break;
+
case HEX_SYS_FTELL:
{
int fd;
--
2.37.2
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [PATCH 11/14] target/hexagon: add OPEN/READ/CLOSE_DIR semihosting operations
2026-07-13 20:07 [PATCH 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
` (9 preceding siblings ...)
2026-07-13 20:07 ` [PATCH 10/14] target/hexagon: add COREDUMP semihosting operation Matheus Tavares Bernardino
@ 2026-07-13 20:07 ` Matheus Tavares Bernardino
2026-07-13 22:33 ` Pierrick Bouvier
2026-07-13 20:07 ` [PATCH 12/14] target/hexagon: Add an errno mapping Matheus Tavares Bernardino
` (3 subsequent siblings)
14 siblings, 1 reply; 37+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-13 20:07 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, pierrick.bouvier, marco.liebel, philmd, ale, anjo,
Matheus Tavares Bernardino
From: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
Baremetal Hexagon programs use semihosting to enumerate host
directories via OPENDIR, READDIR, and CLOSEDIR calls. Track
open directory handles per-CPU in a GList so that guest
index values map back to host DIR pointers across calls.
Signed-off-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
target/hexagon/cpu.h | 1 +
hw/hexagon/hexagon_dsp.c | 5 +++
hw/hexagon/virt.c | 5 +++
target/hexagon/hexswi.c | 79 ++++++++++++++++++++++++++++++++++++++++
4 files changed, 90 insertions(+)
diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h
index 7694fd91fa8..536843584f4 100644
--- a/target/hexagon/cpu.h
+++ b/target/hexagon/cpu.h
@@ -144,6 +144,7 @@ typedef struct CPUArchState {
uint32_t tlb_lock_count;
uint32_t k0_lock_count;
uint64_t t_cycle_count;
+ GList **g_dir_list;
#endif
uint32_t next_PC;
target_ulong new_value_usr;
diff --git a/hw/hexagon/hexagon_dsp.c b/hw/hexagon/hexagon_dsp.c
index 315733cded3..be47daa0d82 100644
--- a/hw/hexagon/hexagon_dsp.c
+++ b/hw/hexagon/hexagon_dsp.c
@@ -147,6 +147,7 @@ static void hexagon_common_init(MachineState *machine, Rev_t rev,
for (int i = 0; i < machine->smp.cpus; i++) {
HexagonCPU *cpu = HEXAGON_CPU(object_new(machine->cpu_type));
+ CPUHexagonState *env = &cpu->env;
qemu_register_reset(do_cpu_reset, cpu);
/*
@@ -156,6 +157,10 @@ static void hexagon_common_init(MachineState *machine, Rev_t rev,
qdev_prop_set_bit(DEVICE(cpu), "start-powered-off", (i != 0));
if (i == 0) {
hexagon_init_bootstrap(dms, cpu);
+ env->g_dir_list = g_malloc0(sizeof(GList *));
+ } else {
+ CPUHexagonState *env0 = cpu_env(qemu_get_cpu(0));
+ env->g_dir_list = env0->g_dir_list;
}
object_property_set_link(OBJECT(cpu), "global-regs",
OBJECT(glob_regs_dev), &error_fatal);
diff --git a/hw/hexagon/virt.c b/hw/hexagon/virt.c
index a3638998b87..62100c08277 100644
--- a/hw/hexagon/virt.c
+++ b/hw/hexagon/virt.c
@@ -283,10 +283,12 @@ static void virt_init(MachineState *ms)
cpu0 = NULL;
for (int i = 0; i < ms->smp.cpus; i++) {
HexagonCPU *cpu = HEXAGON_CPU(object_new(ms->cpu_type));
+ CPUHexagonState *env = &cpu->env;
qemu_register_reset(do_cpu_reset, cpu);
if (i == 0) {
cpu0 = DEVICE(cpu);
+ env->g_dir_list = g_malloc0(sizeof(GList *));
if (ms->kernel_filename) {
uint64_t entry = load_kernel(vms);
qdev_prop_set_uint32(cpu0, "exec-start-addr", entry);
@@ -294,6 +296,9 @@ static void virt_init(MachineState *ms)
uint64_t entry = load_bios(vms);
qdev_prop_set_uint32(cpu0, "exec-start-addr", entry);
}
+ } else {
+ CPUHexagonState *env0 = cpu_env(qemu_get_cpu(0));
+ env->g_dir_list = env0->g_dir_list;
}
qdev_prop_set_uint32(DEVICE(cpu), "htid", i);
qdev_prop_set_bit(DEVICE(cpu), "start-powered-off", (i != 0));
diff --git a/target/hexagon/hexswi.c b/target/hexagon/hexswi.c
index 7efd33d3533..edadb40bed6 100644
--- a/target/hexagon/hexswi.c
+++ b/target/hexagon/hexswi.c
@@ -30,6 +30,9 @@
#include "semihosting/guestfd.h"
#include "system/runstate.h"
+/* We start from 1 as 0 is used to signal an error from opendir() */
+static const int DIR_INDEX_OFFSET = 1;
+
/* non-arm-compatible semihosting calls */
#define HEXAGON_SPECIFIC_SWI_FLAGS \
DEF_SWI_FLAG(OPEN, 0x01) \
@@ -566,6 +569,82 @@ static void sim_handle_trap0(CPUHexagonState *env)
}
break;
+ case HEX_SYS_OPENDIR:
+ {
+ DIR *dir;
+ char buf[BUFSIZ];
+ int rc = 0, err = 0;
+ int i = 0;
+
+ do {
+ hexagon_read_memory(env, swi_info + i, 1, &buf[i], retaddr);
+ i++;
+ } while ((i < BUFSIZ) && buf[i - 1]);
+
+ dir = opendir(buf);
+ if (dir != NULL) {
+ *env->g_dir_list = g_list_append(*env->g_dir_list, dir);
+ rc = g_list_index(*env->g_dir_list, dir) + DIR_INDEX_OFFSET;
+ } else {
+ err = errno;
+ }
+ common_semi_cb(cs, rc, rc != 0 ? 0 : err);
+ break;
+ }
+
+ case HEX_SYS_READDIR:
+ {
+ struct dirent *host_dir_entry = NULL;
+ int dir_index = swi_info - DIR_INDEX_OFFSET;
+ DIR *dir = g_list_nth_data(*env->g_dir_list, dir_index);
+ uint32_t rc = 0, err = 0;
+
+ if (dir) {
+ errno = 0;
+ host_dir_entry = readdir(dir);
+ if (host_dir_entry == NULL) {
+ err = errno;
+ }
+ } else {
+ err = EBADF;
+ }
+
+ if (host_dir_entry) {
+ uint32_t guest_dir_entry = arch_get_thread_reg(env, HEX_REG_R02);
+ hexagon_write_memory(env, guest_dir_entry, 4, host_dir_entry->d_ino,
+ retaddr);
+ for (int i = 0; i < sizeof(host_dir_entry->d_name); i++) {
+ hexagon_write_memory(env, guest_dir_entry + 4 + i, 1,
+ host_dir_entry->d_name[i], retaddr);
+ if (!host_dir_entry->d_name[i]) {
+ break;
+ }
+ }
+ rc = guest_dir_entry;
+ }
+ common_semi_cb(cs, rc, err);
+ break;
+ }
+
+ case HEX_SYS_CLOSEDIR:
+ {
+ DIR *dir;
+ int ret = -1, err = 0;
+ int dir_index = swi_info - DIR_INDEX_OFFSET;
+
+ dir = g_list_nth_data(*env->g_dir_list, dir_index);
+ if (dir != NULL) {
+ ret = closedir(dir);
+ if (ret != 0) {
+ err = errno;
+ }
+ } else {
+ err = EBADF;
+ }
+ common_semi_cb(cs, ret, ret == 0 ? 0 : err);
+ break;
+ }
+
case HEX_SYS_COREDUMP:
coredump(env);
break;
--
2.37.2
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [PATCH 12/14] target/hexagon: Add an errno mapping
2026-07-13 20:07 [PATCH 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
` (10 preceding siblings ...)
2026-07-13 20:07 ` [PATCH 11/14] target/hexagon: add OPEN/READ/CLOSE_DIR semihosting operations Matheus Tavares Bernardino
@ 2026-07-13 20:07 ` Matheus Tavares Bernardino
2026-07-13 22:23 ` Pierrick Bouvier
2026-07-13 20:07 ` [PATCH 13/14] python/machine: support routing semihosting output to the test console Matheus Tavares Bernardino
` (2 subsequent siblings)
14 siblings, 1 reply; 37+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-13 20:07 UTC (permalink / raw)
To: qemu-devel; +Cc: brian.cain, pierrick.bouvier, marco.liebel, philmd, ale, anjo
From: Brian Cain <brian.cain@oss.qualcomm.com>
The Hexagon semihosting ABI defines its own errno values
which may differ from the host's. Translate host errno to
the Hexagon-specific values before returning results to the
guest so that baremetal programs see the expected error codes.
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
---
target/hexagon/hexswi.c | 81 +++++++++++++++++++++++++++++++++--------
1 file changed, 66 insertions(+), 15 deletions(-)
diff --git a/target/hexagon/hexswi.c b/target/hexagon/hexswi.c
index edadb40bed6..81fe3d5046d 100644
--- a/target/hexagon/hexswi.c
+++ b/target/hexagon/hexswi.c
@@ -122,12 +122,63 @@ static void do_preload(CPUHexagonState *env, target_ulong swi_info, bool load)
hexagon_touch_memory(env, addr, count, retaddr);
}
+/* Hexagon semihosting errno values */
+#define HEX_EINVAL 22
+#define HEX_ERRNOS \
+ HEX_ERRNO(EPERM, 1) \
+ HEX_ERRNO(ENOENT, 2) \
+ HEX_ERRNO(EINTR, 4) \
+ HEX_ERRNO(EIO, 5) \
+ HEX_ERRNO(ENXIO, 6) \
+ HEX_ERRNO(EBADF, 9) \
+ HEX_ERRNO(EAGAIN, 11) \
+ HEX_ERRNO(ENOMEM, 12) \
+ HEX_ERRNO(EACCES, 13) \
+ HEX_ERRNO(EFAULT, 14) \
+ HEX_ERRNO(EBUSY, 16) \
+ HEX_ERRNO(EEXIST, 17) \
+ HEX_ERRNO(EXDEV, 18) \
+ HEX_ERRNO(ENODEV, 19) \
+ HEX_ERRNO(ENOTDIR, 20) \
+ HEX_ERRNO(EISDIR, 21) \
+ HEX_ERRNO(EINVAL, HEX_EINVAL) \
+ HEX_ERRNO(ENFILE, 23) \
+ HEX_ERRNO(EMFILE, 24) \
+ HEX_ERRNO(ENOTTY, 25) \
+ HEX_ERRNO(ETXTBSY, 26) \
+ HEX_ERRNO(EFBIG, 27) \
+ HEX_ERRNO(ENOSPC, 28) \
+ HEX_ERRNO(ESPIPE, 29) \
+ HEX_ERRNO(EROFS, 30) \
+ HEX_ERRNO(EMLINK, 31) \
+ HEX_ERRNO(EPIPE, 32) \
+ HEX_ERRNO(ERANGE, 34) \
+ HEX_ERRNO(ENAMETOOLONG, 36) \
+ HEX_ERRNO(ENOSYS, 38) \
+ HEX_ERRNO(ELOOP, 40) \
+ HEX_ERRNO(EOVERFLOW, 75)
+
+/* Map host errno to hexagon semihosting errno */
+static void semi_cb(CPUState *cs, uint64_t ret, int err)
+{
+#define HEX_ERRNO(NAME, CODE) case NAME: err = CODE; break;
+ switch (err) {
+ case 0:
+ break;
+ HEX_ERRNOS
+ default:
+ err = HEX_EINVAL;
+ break;
+ }
+ common_semi_cb(cs, ret, err);
+}
+
static void common_semi_ftell_cb(CPUState *cs, uint64_t ret, int err)
{
if (err) {
ret = -1;
}
- common_semi_cb(cs, ret, err);
+ semi_cb(cs, ret, err);
}
static void coredump(CPUHexagonState *env)
@@ -360,7 +411,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;
}
@@ -377,7 +428,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;
}
@@ -396,7 +447,7 @@ static void sim_handle_trap0(CPUHexagonState *env)
ret = guestfd;
}
}
- common_semi_cb(cs, ret, err);
+ semi_cb(cs, ret, err);
}
break;
@@ -415,7 +466,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;
@@ -496,7 +547,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;
@@ -506,7 +557,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;
@@ -530,7 +581,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;
@@ -558,14 +609,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;
@@ -588,7 +639,7 @@ static void sim_handle_trap0(CPUHexagonState *env)
} else {
err = errno;
}
- common_semi_cb(cs, rc, rc != 0 ? 0 : err);
+ semi_cb(cs, rc, rc != 0 ? 0 : err);
break;
}
@@ -622,7 +673,7 @@ static void sim_handle_trap0(CPUHexagonState *env)
}
rc = guest_dir_entry;
}
- common_semi_cb(cs, rc, err);
+ semi_cb(cs, rc, err);
break;
}
@@ -641,7 +692,7 @@ static void sim_handle_trap0(CPUHexagonState *env)
} else {
err = EBADF;
}
- common_semi_cb(cs, ret, ret == 0 ? 0 : err);
+ semi_cb(cs, ret, ret == 0 ? 0 : err);
break;
}
@@ -680,7 +731,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",
@@ -693,7 +744,7 @@ static void sim_handle_trap0(CPUHexagonState *env)
qemu_log_mask(LOG_GUEST_ERROR,
"unknown swi request: 0x%" PRIx32 "\n",
(uint32_t)what_swi);
- common_semi_cb(cs, -1, ENOSYS);
+ semi_cb(cs, -1, ENOSYS);
}
}
--
2.37.2
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [PATCH 13/14] python/machine: support routing semihosting output to the test console
2026-07-13 20:07 [PATCH 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
` (11 preceding siblings ...)
2026-07-13 20:07 ` [PATCH 12/14] target/hexagon: Add an errno mapping Matheus Tavares Bernardino
@ 2026-07-13 20:07 ` Matheus Tavares Bernardino
2026-07-13 22:23 ` Pierrick Bouvier
2026-07-13 20:07 ` [PATCH 14/14] tests/functional: Add hexagon semihosting systests Matheus Tavares Bernardino
2026-07-13 21:51 ` [PATCH 00/14] hexagon: add semihosting support Pierrick Bouvier
14 siblings, 1 reply; 37+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-13 20:07 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, pierrick.bouvier, marco.liebel, philmd, ale, anjo,
John Snow, Cleber Rosa
From: Brian Cain <brian.cain@oss.qualcomm.com>
The hexagon semihosting systests will wait for output on the semihosting
console.
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
---
python/qemu/machine/machine.py | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/python/qemu/machine/machine.py b/python/qemu/machine/machine.py
index bfb59d4c0bf..39375065558 100644
--- a/python/qemu/machine/machine.py
+++ b/python/qemu/machine/machine.py
@@ -186,6 +186,7 @@ def __init__(self,
self._console_index = 0
self._console_set = False
self._console_device_type: Optional[str] = None
+ self._console_semihosting = False
self._console_socket: Optional[socket.socket] = None
self._console_file: Optional[socket.SocketIO] = None
self._remove_files: List[str] = []
@@ -321,7 +322,10 @@ def _console_args(self, interactive: bool = False) -> List[str]:
fd = self._cons_sock_pair[0].fileno()
chardev = f"socket,id=console,fd={fd}"
args.extend(['-chardev', chardev])
- if self._console_device_type is None:
+ if self._console_semihosting:
+ args.extend(['-semihosting-config',
+ 'enable=on,chardev=console'])
+ elif self._console_device_type is None:
args.extend(['-serial', 'chardev:console'])
else:
device = '%s,chardev=console' % self._console_device_type
@@ -892,7 +896,8 @@ def set_machine(self, machine_type: str) -> None:
def set_console(self,
device_type: Optional[str] = None,
- console_index: int = 0) -> None:
+ console_index: int = 0,
+ semihosting: bool = False) -> None:
"""
Sets the device type for a console device
@@ -921,6 +926,7 @@ def set_console(self,
self._console_set = True
self._console_device_type = device_type
self._console_index = console_index
+ self._console_semihosting = semihosting
@property
def console_socket(self) -> socket.socket:
--
2.37.2
^ permalink raw reply related [flat|nested] 37+ messages in thread
* [PATCH 14/14] tests/functional: Add hexagon semihosting systests
2026-07-13 20:07 [PATCH 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
` (12 preceding siblings ...)
2026-07-13 20:07 ` [PATCH 13/14] python/machine: support routing semihosting output to the test console Matheus Tavares Bernardino
@ 2026-07-13 20:07 ` Matheus Tavares Bernardino
2026-07-13 22:28 ` Pierrick Bouvier
2026-07-14 8:25 ` Daniel P. Berrangé
2026-07-13 21:51 ` [PATCH 00/14] hexagon: add semihosting support Pierrick Bouvier
14 siblings, 2 replies; 37+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-13 20:07 UTC (permalink / raw)
To: qemu-devel
Cc: brian.cain, pierrick.bouvier, marco.liebel, philmd, ale, anjo,
Thomas Huth, Philippe Mathieu-Daudé, Daniel P. Berrangé
From: Brian Cain <brian.cain@oss.qualcomm.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
---
tests/functional/hexagon/meson.build | 9 ++
tests/functional/hexagon/test_systests.py | 133 ++++++++++++++++++++++
tests/functional/meson.build | 1 +
3 files changed, 143 insertions(+)
create mode 100644 tests/functional/hexagon/meson.build
create mode 100644 tests/functional/hexagon/test_systests.py
diff --git a/tests/functional/hexagon/meson.build b/tests/functional/hexagon/meson.build
new file mode 100644
index 00000000000..6cd684b0df7
--- /dev/null
+++ b/tests/functional/hexagon/meson.build
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+test_hexagon_timeouts = {
+ 'systests': 180,
+}
+
+tests_hexagon_system_thorough = [
+ 'systests',
+]
diff --git a/tests/functional/hexagon/test_systests.py b/tests/functional/hexagon/test_systests.py
new file mode 100644
index 00000000000..b20b9fc56cc
--- /dev/null
+++ b/tests/functional/hexagon/test_systests.py
@@ -0,0 +1,133 @@
+#!/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 = os.path.join(
+ "systests_standalone_package",
+ "StandaloneSysTests_6.4.0.2_v68",
+ "bin",
+)
+
+
+class SysTestsStandaloneTests(QemuSystemTest):
+ SYSTEST_TIMEOUT_SEC = 30
+
+ ASSET_TARBALL = Asset(
+ "https://github.com/qualcomm/qemu-hexagon-testing/releases/download/v0.2.9/systests_standalone.tar.gz",
+ "db961ea3fcc389b478b3d5c2f3bac60bec87e7f3d7efef5e58a9ae8ee78d0e40",
+ )
+
+ def setUp(self):
+ super().setUp()
+ self.archive_extract(self.ASSET_TARBALL)
+ self.bin_dir = os.path.join(self.workdir, _TARBALL_BIN_PATH)
+ self._orig_cwd = os.getcwd()
+ os.chdir(self.workdir)
+ self.addCleanup(os.chdir, self._orig_cwd)
+
+ def tearDown(self):
+ if hasattr(self, "_orig_cwd"):
+ os.chdir(self._orig_cwd)
+ super().tearDown()
+
+ def binary(self, name):
+ """Return the full path to binary *name* inside bin_dir."""
+ return os.path.join(self.bin_dir, name)
+
+ def run_exit_zero(self, binary_name, *extra_args, machine="V66G_1024"):
+ """Launch *binary_name* and assert it exits with code 0.
+
+ :param binary_name: name of the binary inside bin_dir.
+ :param extra_args: optional pairs of (flag, value) strings passed
+ to set_vm_arg(), e.g. ('-append', 'myarg').
+ :param machine: QEMU machine type (default "V66G_1024").
+ """
+ self.set_machine(machine)
+ self.set_vm_arg("-display", "none")
+ self.set_vm_arg("-kernel", self.binary(binary_name))
+ for flag, value in zip(extra_args[::2], extra_args[1::2]):
+ self.set_vm_arg(flag, value)
+ self.vm.launch()
+ self.vm.wait(timeout=60.0)
+ self.assertEqual(self.vm.exitcode(), 0,
+ f"Test {binary_name} exited with "
+ f"code {self.vm.exitcode()}, expected 0")
+
+ def run_console_pattern(self, binary_name, pattern, *extra_args,
+ machine="V66G_1024"):
+ """Launch *binary_name* and wait for *pattern* on the semihosting console.
+
+ :param binary_name: name of the binary inside bin_dir.
+ :param pattern: string pattern to wait for via wait_for_console_pattern.
+ :param extra_args: optional pairs of (flag, value) strings passed
+ to set_vm_arg(), e.g. ('-append', 'myarg').
+ :param machine: QEMU machine type (default "V66G_1024").
+ """
+ self.set_machine(machine)
+ self.set_vm_arg("-display", "none")
+ self.set_vm_arg("-kernel", self.binary(binary_name))
+ for flag, value in zip(extra_args[::2], extra_args[1::2]):
+ self.set_vm_arg(flag, value)
+ self.vm.set_console(semihosting=True)
+ self.vm.launch()
+ try:
+ wait_for_console_pattern(self, pattern)
+ finally:
+ self.vm.kill()
+
+ def test_fopen(self):
+ """fopen reads a file passed via --append and verifies its contents."""
+ with open(os.path.join(self.workdir, "dummy.so"), "w") as f:
+ f.write("valid\n")
+ self.run_exit_zero("fopen", "-append", "dummy.so")
+
+ def test_ftrunc(self):
+ """ftrunc truncates _testfile_ftrunc from 6 bytes to 1 byte."""
+ ftrunc_path = os.path.join(self.workdir, "_testfile_ftrunc")
+ with open(ftrunc_path, "w") as f:
+ f.write("valid\n")
+ # Sleep 1 s so mtime change is observable
+ time.sleep(1)
+ self.run_exit_zero("ftrunc")
+ self.assertEqual(
+ os.path.getsize(ftrunc_path),
+ 1,
+ "_testfile_ftrunc should be 1 byte after ftrunc",
+ )
+
+ def test_dirent(self):
+ """dirent lists a directory passed via --append; output must be
+ '. .. fileA fileB'."""
+ dirent_dir = os.path.join(self.workdir, "_dirent_testdir")
+ os.makedirs(dirent_dir, exist_ok=True)
+ open(os.path.join(dirent_dir, "fileA"), "w").close()
+ open(os.path.join(dirent_dir, "fileB"), "w").close()
+ self.run_console_pattern(
+ "dirent", ". .. fileA fileB", "-append", "_dirent_testdir"
+ )
+
+ def test_access(self):
+ """access checks R_OK|W_OK on _testfile_access."""
+ with open(os.path.join(self.workdir, "_testfile_access"), "w") as f:
+ f.write("valid\n")
+ self.run_exit_zero("access")
+
+ def test_semihost(self):
+ semihost_dir = os.path.join(self.workdir, "_semihost_dir")
+ os.makedirs(semihost_dir, exist_ok=True)
+ open(os.path.join(semihost_dir, "fileA"), "w").close()
+ open(os.path.join(semihost_dir, "fileB"), "w").close()
+ self.run_console_pattern("semihost", "PASS", "-append", "arg1", "arg2")
+
+if __name__ == "__main__":
+ QemuSystemTest.main()
diff --git a/tests/functional/meson.build b/tests/functional/meson.build
index c158197c4b7..c7362dd00ef 100644
--- a/tests/functional/meson.build
+++ b/tests/functional/meson.build
@@ -14,6 +14,7 @@ subdir('aarch64')
subdir('alpha')
subdir('arm')
subdir('avr')
+subdir('hexagon')
subdir('hppa')
subdir('i386')
subdir('loongarch64')
--
2.37.2
^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [PATCH 01/14] target/hexagon: fix get_phys_addr_debug with in-page offset
2026-07-13 20:07 ` [PATCH 01/14] target/hexagon: fix get_phys_addr_debug with in-page offset Matheus Tavares Bernardino
@ 2026-07-13 21:41 ` Pierrick Bouvier
0 siblings, 0 replies; 37+ messages in thread
From: Pierrick Bouvier @ 2026-07-13 21:41 UTC (permalink / raw)
To: Matheus Tavares Bernardino, qemu-devel
Cc: brian.cain, marco.liebel, philmd, ale, anjo
On 7/13/2026 1:07 PM, Matheus Tavares Bernardino wrote:
> As documented:
>
> * @get_phys_addr_debug: Callback for obtaining a physical address.
> * This must be able to handle a non-page-aligned address, and will
> * return the physical address corresponding to that address.
>
> When MMU is enabled, hexagon_cpu_get_phys_addr_debug() returns the
> physical address page-aligned, not corrected to reflect the exact byte
> the virtual addr maps to within the page. Let's fix that. The
> MMU-disabled case is already correct.
>
> This would break semihosting argument reads when it is added for Hexagon.
>
> Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
> ---
> target/hexagon/cpu.c | 2 ++
> 1 file changed, 2 insertions(+)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 00/14] hexagon: add semihosting support
2026-07-13 20:07 [PATCH 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
` (13 preceding siblings ...)
2026-07-13 20:07 ` [PATCH 14/14] tests/functional: Add hexagon semihosting systests Matheus Tavares Bernardino
@ 2026-07-13 21:51 ` Pierrick Bouvier
14 siblings, 0 replies; 37+ messages in thread
From: Pierrick Bouvier @ 2026-07-13 21:51 UTC (permalink / raw)
To: Matheus Tavares Bernardino, qemu-devel
Cc: brian.cain, marco.liebel, philmd, ale, anjo
Hi Matheus,
On 7/13/2026 1:07 PM, Matheus Tavares Bernardino wrote:
> 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
>
> Brian Cain (4):
> semihosting: add APIs for chardev-aware guest fd routing
> target/hexagon: Add an errno mapping
> python/machine: support routing semihosting output to the test console
> tests/functional: Add hexagon semihosting systests
>
> Matheus Tavares Bernardino (10):
> target/hexagon: fix get_phys_addr_debug with in-page offset
> target/hexagon: fix PC advancement for non-COF TB terminators
> target/hexagon: add aux functions for guest mem load/store
> hexagon: cpu_helper: add reg reading/writing helpers
> semihosting: add callback to set error
> target/hexagon: add semihosting support
> semihosting: add ftruncate helper (to be used for hexagon)
> target/hexagon: add main arch-specific semihosting operations
> target/hexagon: add COREDUMP semihosting operation
> target/hexagon: add OPEN/READ/CLOSE_DIR semihosting operations
>
> configs/targets/hexagon-softmmu.mak | 2 +
> include/semihosting/common-semi.h | 2 +
> include/semihosting/console.h | 9 +
> include/semihosting/guestfd.h | 9 +
> include/semihosting/syscalls.h | 2 +
> target/hexagon/cpu.h | 1 +
> target/hexagon/cpu_helper.h | 24 +
> target/hexagon/internal.h | 1 +
> hw/hexagon/hexagon_dsp.c | 7 +
> hw/hexagon/virt.c | 5 +
> 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 | 4 +-
> target/hexagon/cpu_helper.c | 173 +++++
> target/hexagon/hexswi.c | 728 +++++++++++++++++++++-
> target/hexagon/op_helper.c | 18 +-
> target/hexagon/translate.c | 13 +-
> target/riscv/common-semi-target.c | 4 +
> hw/hexagon/Kconfig | 1 +
> python/qemu/machine/machine.py | 10 +-
> qemu-options.hx | 8 +-
> target/hexagon/meson.build | 3 +
> tests/functional/hexagon/meson.build | 9 +
> tests/functional/hexagon/test_systests.py | 133 ++++
> tests/functional/meson.build | 1 +
> 29 files changed, 1236 insertions(+), 31 deletions(-)
> create mode 100644 target/hexagon/common-semi-target.c
> create mode 100644 tests/functional/hexagon/meson.build
> create mode 100644 tests/functional/hexagon/test_systests.py
>
see some build failures on windows and macos.
(feel free to ignore other one, seems to be a network outage issue).
Also, a few checkpatch style issues.
https://github.com/p-b-o/qemu-ci/actions/runs/29283651823
Regards,
Pierrick
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 02/14] target/hexagon: fix PC advancement for non-COF TB terminators
2026-07-13 20:07 ` [PATCH 02/14] target/hexagon: fix PC advancement for non-COF TB terminators Matheus Tavares Bernardino
@ 2026-07-13 21:53 ` Pierrick Bouvier
0 siblings, 0 replies; 37+ messages in thread
From: Pierrick Bouvier @ 2026-07-13 21:53 UTC (permalink / raw)
To: Matheus Tavares Bernardino, qemu-devel
Cc: brian.cain, marco.liebel, philmd, ale, anjo
On 7/13/2026 1:07 PM, Matheus Tavares Bernardino wrote:
> 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.
>
> Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
> ---
> target/hexagon/translate.c | 13 +++++++++----
> 1 file changed, 9 insertions(+), 4 deletions(-)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 03/14] target/hexagon: add aux functions for guest mem load/store
2026-07-13 20:07 ` [PATCH 03/14] target/hexagon: add aux functions for guest mem load/store Matheus Tavares Bernardino
@ 2026-07-13 21:58 ` Pierrick Bouvier
2026-07-14 10:17 ` Matheus Tavares Bernardino
0 siblings, 1 reply; 37+ messages in thread
From: Pierrick Bouvier @ 2026-07-13 21:58 UTC (permalink / raw)
To: Matheus Tavares Bernardino, qemu-devel
Cc: brian.cain, marco.liebel, philmd, ale, anjo,
Matheus Tavares Bernardino
On 7/13/2026 1:07 PM, Matheus Tavares Bernardino wrote:
> From: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
>
> Will be used for semihosting.
>
> Signed-off-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> ---
> target/hexagon/cpu_helper.h | 6 ++
> target/hexagon/cpu_helper.c | 133 ++++++++++++++++++++++++++++++++++++
> 2 files changed, 139 insertions(+)
>
> diff --git a/target/hexagon/cpu_helper.h b/target/hexagon/cpu_helper.h
> index d1767503156..f6a31ecbab0 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_touch_memory(CPUHexagonState *env, uint32_t start_addr,
> + uint32_t length, uintptr_t retaddr);
> uint32_t hexagon_get_pmu_counter(CPUHexagonState *cur_env, int index);
> void hexagon_modify_ssr(CPUHexagonState *env, uint32_t new, uint32_t old);
> int get_cpu_mode(CPUHexagonState *env);
> diff --git a/target/hexagon/cpu_helper.c b/target/hexagon/cpu_helper.c
> index 64c5746c6d9..1ab2564e3dc 100644
> --- a/target/hexagon/cpu_helper.c
> +++ b/target/hexagon/cpu_helper.c
> @@ -25,6 +25,139 @@
> #include "sys_macros.h"
> #include "arch.h"
>
> +#ifndef CONFIG_USER_ONLY
> +
> +static bool hexagon_read_memory_small(CPUHexagonState *env, target_ulong addr,
> + int byte_count, unsigned char *dstbuf,
> + int mmu_idx, uintptr_t retaddr)
> + {
> + /* handle small sizes */
> + switch (byte_count) {
> + case 1:
> + *dstbuf = cpu_ldub_mmuidx_ra(env, addr, mmu_idx, retaddr);
> + return true;
> +
> + case 2:
> + if (QEMU_IS_ALIGNED(addr, 2)) {
> + *(unsigned short *)dstbuf =
> + cpu_lduw_le_mmuidx_ra(env, addr, mmu_idx, retaddr);
> + return true;
> + }
> + break;
> +
> + case 4:
> + if (QEMU_IS_ALIGNED(addr, 4)) {
> + *(uint32_t *)dstbuf =
> + cpu_ldl_le_mmuidx_ra(env, addr, mmu_idx, retaddr);
> + return true;
> + }
> + break;
> +
> + case 8:
> + if (QEMU_IS_ALIGNED(addr, 8)) {
> + *(uint64_t *)dstbuf =
> + cpu_ldq_le_mmuidx_ra(env, addr, mmu_idx, retaddr);
> + return true;
> + }
> + break;
> +
> + default:
> + /* larger request, handle elsewhere */
> + return false;
> + }
> +
> + /* not aligned, copy bytes */
> + for (int i = 0; i < byte_count; ++i) {
> + *dstbuf++ = cpu_ldub_mmuidx_ra(env, addr++, mmu_idx, retaddr);
> + }
> + return true;
> +}
> +
> +void hexagon_read_memory(CPUHexagonState *env, target_ulong vaddr, int size,
> + void *retptr, uintptr_t retaddr)
> +{
> + BQL_LOCK_GUARD();
> + CPUState *cs = env_cpu(env);
> + unsigned mmu_idx = cpu_mmu_index(cs, false);
> + if (!hexagon_read_memory_small(env, vaddr, size, retptr, mmu_idx,
> + retaddr)) {
> + cpu_abort(cs, "%s: ERROR: bad size = %d!\n", __func__, size);
> + }
> +}
> +
> +static bool hexagon_write_memory_small(CPUHexagonState *env, target_ulong addr,
> + int byte_count, unsigned char *srcbuf,
> + int mmu_idx, uintptr_t retaddr)
> +{
> + /* handle small sizes */
> + switch (byte_count) {
> + case 1:
> + cpu_stb_mmuidx_ra(env, addr, *srcbuf, mmu_idx, retaddr);
> + return true;
> +
> + case 2:
> + if (QEMU_IS_ALIGNED(addr, 2)) {
> + cpu_stw_le_mmuidx_ra(env, addr, *(uint16_t *)srcbuf, mmu_idx, retaddr);
> + return true;
> + }
> + break;
> +
> + case 4:
> + if (QEMU_IS_ALIGNED(addr, 4)) {
> + cpu_stl_le_mmuidx_ra(env, addr, *(uint32_t *)srcbuf, mmu_idx, retaddr);
> + return true;
> + }
> + break;
> +
> + case 8:
> + if (QEMU_IS_ALIGNED(addr, 8)) {
> + cpu_stq_le_mmuidx_ra(env, addr, *(uint64_t *)srcbuf, mmu_idx, retaddr);
> + return true;
> + }
> + break;
> +
> + default:
> + /* larger request, handle elsewhere */
> + return false;
> + }
> +
> + /* not aligned, copy bytes */
> + for (int i = 0; i < byte_count; ++i) {
> + cpu_stb_mmuidx_ra(env, addr++, *srcbuf++, mmu_idx, retaddr);
> + }
> +
> + return true;
> +}
> +
> +void hexagon_write_memory(CPUHexagonState *env, target_ulong vaddr,
> + int size, uint64_t data, uintptr_t retaddr)
> +{
> + CPUState *cs = env_cpu(env);
> + unsigned mmu_idx = cpu_mmu_index(cs, false);
> + if (!hexagon_write_memory_small(env, vaddr, size, (unsigned char *)&data,
> + mmu_idx, retaddr)) {
> + cpu_abort(cs, "%s: ERROR: bad size = %d!\n", __func__, size);
> + }
> +}
> +
> +static inline uint32_t page_start(uint32_t addr)
> +{
> + uint32_t page_align = ~(TARGET_PAGE_SIZE - 1);
> + return addr & page_align;
> +}
> +
> +void hexagon_touch_memory(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);
> + }
> +}
> +
Name could be misleading, I would be expectng to see a read/write
sequence in each page instead of just reading.
Maybe hexagon_peek_memory_range?
> +#endif
>
> uint32_t hexagon_get_pmu_counter(CPUHexagonState *cur_env, int index)
> {
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Regards,
Pierrick
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 04/14] hexagon: cpu_helper: add reg reading/writing helpers
2026-07-13 20:07 ` [PATCH 04/14] hexagon: cpu_helper: add reg reading/writing helpers Matheus Tavares Bernardino
@ 2026-07-13 22:00 ` Pierrick Bouvier
0 siblings, 0 replies; 37+ messages in thread
From: Pierrick Bouvier @ 2026-07-13 22:00 UTC (permalink / raw)
To: Matheus Tavares Bernardino, qemu-devel
Cc: brian.cain, marco.liebel, philmd, ale, anjo
On 7/13/2026 1:07 PM, Matheus Tavares Bernardino wrote:
> And adjust op_helper to use those. They will also be used on upcoming
> semihosting commits.
>
> Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
> ---
> target/hexagon/cpu_helper.h | 18 +++++++++++++++++
> target/hexagon/cpu_helper.c | 40 +++++++++++++++++++++++++++++++++++++
> target/hexagon/op_helper.c | 18 ++---------------
> 3 files changed, 60 insertions(+), 16 deletions(-)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 05/14] semihosting: add callback to set error
2026-07-13 20:07 ` [PATCH 05/14] semihosting: add callback to set error Matheus Tavares Bernardino
@ 2026-07-13 22:01 ` Pierrick Bouvier
2026-07-14 9:50 ` Daniel Henrique Barboza
1 sibling, 0 replies; 37+ messages in thread
From: Pierrick Bouvier @ 2026-07-13 22:01 UTC (permalink / raw)
To: Matheus Tavares Bernardino, qemu-devel
Cc: brian.cain, marco.liebel, philmd, ale, anjo, Alex Bennée,
Peter Maydell, Palmer Dabbelt, Alistair Francis, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, Chao Liu, qemu-arm,
qemu-riscv
On 7/13/2026 1:07 PM, Matheus Tavares Bernardino wrote:
> This is currently unused by existing semihosting targets, but it will be
> used by hexagon.
>
> Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
> Signed-off-by: Brian Cain <brian.cain@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(+)
>
Is it used in this series?
Regards,
Pierrick
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 06/14] semihosting: add APIs for chardev-aware guest fd routing
2026-07-13 20:07 ` [PATCH 06/14] semihosting: add APIs for chardev-aware guest fd routing Matheus Tavares Bernardino
@ 2026-07-13 22:04 ` Pierrick Bouvier
0 siblings, 0 replies; 37+ messages in thread
From: Pierrick Bouvier @ 2026-07-13 22:04 UTC (permalink / raw)
To: Matheus Tavares Bernardino, qemu-devel
Cc: brian.cain, marco.liebel, philmd, ale, anjo, Alex Bennée
On 7/13/2026 1:07 PM, Matheus Tavares Bernardino wrote:
> 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>
> ---
> include/semihosting/console.h | 9 +++++++++
> include/semihosting/guestfd.h | 9 +++++++++
> semihosting/console.c | 5 +++++
> semihosting/guestfd.c | 8 ++++++++
> 4 files changed, 31 insertions(+)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 07/14] target/hexagon: add semihosting support
2026-07-13 20:07 ` [PATCH 07/14] target/hexagon: add semihosting support Matheus Tavares Bernardino
@ 2026-07-13 22:11 ` Pierrick Bouvier
2026-07-14 10:13 ` Matheus Tavares Bernardino
0 siblings, 1 reply; 37+ messages in thread
From: Pierrick Bouvier @ 2026-07-13 22:11 UTC (permalink / raw)
To: Matheus Tavares Bernardino, qemu-devel
Cc: brian.cain, marco.liebel, philmd, ale, anjo,
Matheus Tavares Bernardino, Paolo Bonzini
On 7/13/2026 1:07 PM, Matheus Tavares Bernardino wrote:
> From: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
>
> Baremetal Hexagon programs use trap0 #0 to invoke
> semihosting calls for I/O and process control. Wire up the
> arm-compatible semihosting framework for softmmu by enabling
> CONFIG_ARM_COMPATIBLE_SEMIHOSTING and routing trap0 to the
> semihosting handler.
>
> Signed-off-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> ---
> configs/targets/hexagon-softmmu.mak | 2 +
> hw/hexagon/hexagon_dsp.c | 2 +
> target/hexagon/common-semi-target.c | 51 +++++++++
> target/hexagon/hexswi.c | 164 +++++++++++++++++++++++++++-
> hw/hexagon/Kconfig | 1 +
> qemu-options.hx | 8 +-
> target/hexagon/meson.build | 3 +
> 7 files changed, 224 insertions(+), 7 deletions(-)
> create mode 100644 target/hexagon/common-semi-target.c
>
...
> +static void sim_handle_trap0(CPUHexagonState *env)
> +{
> + target_ulong what_swi, swi_info;
> + G_GNUC_UNUSED uintptr_t retaddr = 0;
leftover?
For the rest:
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Regards,
Pierrick
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 08/14] semihosting: add ftruncate helper (to be used for hexagon)
2026-07-13 20:07 ` [PATCH 08/14] semihosting: add ftruncate helper (to be used for hexagon) Matheus Tavares Bernardino
@ 2026-07-13 22:12 ` Pierrick Bouvier
0 siblings, 0 replies; 37+ messages in thread
From: Pierrick Bouvier @ 2026-07-13 22:12 UTC (permalink / raw)
To: Matheus Tavares Bernardino, qemu-devel
Cc: brian.cain, marco.liebel, philmd, ale, anjo, Alex Bennée
On 7/13/2026 1:07 PM, Matheus Tavares Bernardino wrote:
> 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: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> ---
> include/semihosting/syscalls.h | 2 ++
> semihosting/syscalls.c | 29 +++++++++++++++++++++++++++++
> 2 files changed, 31 insertions(+)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 09/14] target/hexagon: add main arch-specific semihosting operations
2026-07-13 20:07 ` [PATCH 09/14] target/hexagon: add main arch-specific semihosting operations Matheus Tavares Bernardino
@ 2026-07-13 22:20 ` Pierrick Bouvier
2026-07-14 10:10 ` Matheus Tavares Bernardino
0 siblings, 1 reply; 37+ messages in thread
From: Pierrick Bouvier @ 2026-07-13 22:20 UTC (permalink / raw)
To: Matheus Tavares Bernardino, qemu-devel
Cc: brian.cain, marco.liebel, philmd, ale, anjo, Alex Bennée
On 7/13/2026 1:07 PM, Matheus Tavares Bernardino wrote:
> The Hexagon semihosting ABI extends the arm-compatible set with
> operations like OPEN, WRITECREG, WRITE0, ISTTY, STAT, FSTAT, FTELL,
> SEEK, FTRUNC, ACCESS, and GETCWD. Implement these trap0 handlers so
> that baremetal programs using the standard Hexagon simulator ABI can
> perform file I/O when running on qemu-system-hexagon.
>
> Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> ---
> include/semihosting/common-semi.h | 1 +
> semihosting/arm-compat-semi.c | 2 +-
> target/hexagon/hexswi.c | 293 +++++++++++++++++++++++++++++-
> 3 files changed, 294 insertions(+), 2 deletions(-)
>
> diff --git a/include/semihosting/common-semi.h b/include/semihosting/common-semi.h
> index a11905ef4ef..1e7699d7bbd 100644
> --- a/include/semihosting/common-semi.h
> +++ b/include/semihosting/common-semi.h
> @@ -34,6 +34,7 @@
> #ifndef COMMON_SEMI_H
> #define COMMON_SEMI_H
>
> +void common_semi_cb(CPUState *cs, uint64_t ret, int err);
> void do_common_semihosting(CPUState *cs);
> uint64_t common_semi_arg(CPUState *cs, int argno);
> void common_semi_set_ret(CPUState *cs, uint64_t ret);
> diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
> index c54753f696f..b930a028649 100644
> --- a/semihosting/arm-compat-semi.c
> +++ b/semihosting/arm-compat-semi.c
> @@ -229,7 +229,7 @@ static inline uint32_t get_swi_errno(CPUState *cs)
> #endif
> }
>
> -static void common_semi_cb(CPUState *cs, uint64_t ret, int err)
> +void common_semi_cb(CPUState *cs, uint64_t ret, int err)
> {
> if (err) {
> #ifdef CONFIG_USER_ONLY
> diff --git a/target/hexagon/hexswi.c b/target/hexagon/hexswi.c
> index ce9c85ad6aa..2c60e4d9e9f 100644
> --- a/target/hexagon/hexswi.c
> +++ b/target/hexagon/hexswi.c
> @@ -119,6 +119,14 @@ static void do_preload(CPUHexagonState *env, target_ulong swi_info, bool load)
> hexagon_touch_memory(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;
> @@ -174,7 +182,290 @@ static void sim_handle_trap0(CPUHexagonState *env)
> qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
> break;
>
> - /* TODO: implement other hexagon-specific semihosting calls */
> +#ifndef _WIN32
> + case HEX_SYS_OPEN:
> + {
> + char filename[BUFSIZ];
> + target_ulong physicalFilenameAddr;
style: physical_filename_addr;
> + unsigned int filemode;
> + int length;
> + int real_openmode;
> + int ret, err = 0;
> + int i = 0;
> + static const unsigned int mode_table[] = {
> + O_RDONLY,
> + O_RDONLY | O_BINARY,
> + O_RDWR,
> + O_RDWR | O_BINARY,
> + O_WRONLY | O_CREAT | O_TRUNC,
> + O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
> + O_RDWR | O_CREAT | O_TRUNC,
> + O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
> + O_WRONLY | O_APPEND | O_CREAT,
> + O_WRONLY | O_APPEND | O_CREAT | O_BINARY,
> + O_RDWR | O_APPEND | O_CREAT,
> + O_RDWR | O_APPEND | O_CREAT | O_BINARY,
> + O_RDWR | O_CREAT,
> + O_RDWR | O_CREAT | O_EXCL
> + };
> +
Better to extract this with a static const, and a useful name.
angel_to_host_filemode_table.
> +
> + hexagon_read_memory(env, swi_info, 4, &physicalFilenameAddr, 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, physicalFilenameAddr + i, 1, &filename[i],
> + retaddr);
> + i++;
> + } while (filename[i - 1]);
> +
> + /* convert ARM ANGEL filemode into host filemode */
> + if (filemode < 14) {
Also, compare to sizeof table introduced, or define a constant.
ANGEL_FILEMODE_MAX = 13.
> + real_openmode = mode_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 out own implementation.
> + */
s/out/our
> + 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:
> + {
> + /*
> + * This must match the caller's definition, it would be in the
> + * caller's angel.h or equivalent header.
> + */
It would be great to move this definition out of this function also.
> + struct __SYS_STAT {
> + uint64_t dev;
> + uint64_t ino;
> + uint32_t mode;
> + uint32_t nlink;
> + uint64_t rdev;
> + uint32_t size;
> + uint32_t __pad1;
> + uint32_t atime;
> + uint32_t mtime;
> + uint32_t ctime;
> + uint32_t __pad2;
> + } sys_stat;
> + struct stat st_buf;
> + uint8_t *st_bufptr = (uint8_t *)&sys_stat;
> + int rc, err = 0;
> + char filename[BUFSIZ];
> + target_ulong physicalFilenameAddr;
> + target_ulong statBufferAddr;
> + hexagon_read_memory(env, swi_info, 4, &physicalFilenameAddr, retaddr);
> +
> + if (what_swi == HEX_SYS_STAT) {
> + int i = 0;
> + do {
> + hexagon_read_memory(env, physicalFilenameAddr + i, 1,
> + &filename[i], retaddr);
> + i++;
> + } while ((i < BUFSIZ) && filename[i - 1]);
> + rc = stat(filename, &st_buf);
> + err = errno;
> + } else {
> + int fd = physicalFilenameAddr;
> + GuestFD *gf = get_guestfd(fd);
> + if (!gf || gf->type != GuestFDHost) {
> + qemu_log_mask(LOG_UNIMP,
> + "fstat semihosting only implemented"
> + " for native mode\n");
> + g_assert_not_reached();
> + }
> + rc = fstat(gf->hostfd, &st_buf);
> + err = errno;
> + }
> + if (rc == 0) {
> + sys_stat.dev = st_buf.st_dev;
> + sys_stat.ino = st_buf.st_ino;
> + sys_stat.mode = st_buf.st_mode;
> + sys_stat.nlink = (uint32_t) st_buf.st_nlink;
> + sys_stat.rdev = st_buf.st_rdev;
> + sys_stat.size = (uint32_t) st_buf.st_size;
> + 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;
> + }
> + hexagon_read_memory(env, swi_info + 4, 4, &statBufferAddr, retaddr);
> +
> + for (int i = 0; i < sizeof(sys_stat); i++) {
> + hexagon_write_memory(env, statBufferAddr + i, 1, st_bufptr[i],
> + retaddr);
> + }
> + common_semi_cb(cs, rc, rc == 0 ? 0 : err);
> + }
> + break;
> +
> + case HEX_SYS_FTRUNC:
> + {
> + int fd;
> + off_t size_limit;
> + hexagon_read_memory(env, swi_info, 4, &fd, retaddr);
> + hexagon_read_memory(env, swi_info + 4, 8, &size_limit, retaddr);
> + semihost_sys_ftruncate(cs, common_semi_cb, fd, size_limit);
> + }
> + break;
> +
> + case HEX_SYS_ACCESS:
> + {
> + char filename[BUFSIZ];
> + uint32_t FileNameAddr;
> + uint32_t BufferMode;
> + int rc;
> +
> + int i = 0;
> +
> + hexagon_read_memory(env, swi_info, 4, &FileNameAddr, retaddr);
> + do {
> + hexagon_read_memory(env, FileNameAddr + i, 1, &filename[i],
> + retaddr);
> + i++;
> + } while ((i < BUFSIZ) && (filename[i - 1]));
> + filename[i] = 0;
> +
> + hexagon_read_memory(env, swi_info + 4, 4, &BufferMode, retaddr);
> +
> + rc = access(filename, BufferMode);
> + common_semi_cb(cs, rc, rc == 0 ? 0 : errno);
> + }
> + break;
> +
> + case HEX_SYS_GETCWD:
> + {
> + char cwdPtr[PATH_MAX];
> + uint32_t BufferAddr;
> + uint32_t BufferSize;
> + uint32_t rc = 0, err = 0;
> +
> + hexagon_read_memory(env, swi_info, 4, &BufferAddr, retaddr);
> + hexagon_read_memory(env, swi_info + 4, 4, &BufferSize, retaddr);
> +
> + if (!getcwd(cwdPtr, PATH_MAX)) {
> + err = errno;
> + } else {
> + size_t cwd_size = strlen(cwdPtr);
> + if (cwd_size > BufferSize) {
> + err = ERANGE;
> + } else {
> + for (int i = 0; i < cwd_size; i++) {
> + hexagon_write_memory(env, BufferAddr + i, 1,
> + (uint64_t)cwdPtr[i], retaddr);
> + }
> + rc = BufferAddr;
> + }
> + }
> + common_semi_cb(cs, rc, rc != 0 ? 0 : err);
> + break;
> + }
> +
> + case HEX_SYS_EXEC:
> + {
> + qemu_log_mask(LOG_UNIMP, "SYS_EXEC is deprecated\n");
> + common_semi_cb(cs, -1, ENOSYS);
> + }
> + break;
> +
> + case HEX_SYS_FTELL:
> + {
> + int fd;
> + hexagon_read_memory(env, swi_info, 4, &fd, retaddr);
> + semihost_sys_lseek(cs, common_semi_ftell_cb, fd, 0, GDB_SEEK_CUR);
> + }
> + break;
> +
> + case HEX_SYS_READ_CYCLES:
> + case HEX_SYS_READ_TCYCLES:
> + case HEX_SYS_READ_ICOUNT:
> + {
> + arch_set_thread_reg(env, HEX_REG_R00, 0);
> + arch_set_thread_reg(env, HEX_REG_R01, 0);
> + break;
> + }
> +
> + case HEX_SYS_READ_PCYCLES:
> + {
> + arch_set_thread_reg(env, HEX_REG_R00,
> + arch_get_system_reg(env, HEX_SREG_PCYCLELO));
> + arch_set_thread_reg(env, HEX_REG_R01,
> + arch_get_system_reg(env, HEX_SREG_PCYCLEHI));
> + break;
> + }
> +
> + case HEX_SYS_PROF_ON:
> + case HEX_SYS_PROF_OFF:
> + case HEX_SYS_PROF_STATSRESET:
> + case HEX_SYS_DUMP_PMU_STATS:
> + case HEX_SYS_HEAPINFO:
> + common_semi_cb(cs, -1, ENOSYS);
> + qemu_log_mask(LOG_UNIMP,
> + "SWI call %" PRIx32
> + " is unimplemented in QEMU\n",
> + (uint32_t)what_swi);
> + break;
> +
> +#endif /* ! _WIN32 */
>
> default:
> qemu_log_mask(LOG_GUEST_ERROR,
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 10/14] target/hexagon: add COREDUMP semihosting operation
2026-07-13 20:07 ` [PATCH 10/14] target/hexagon: add COREDUMP semihosting operation Matheus Tavares Bernardino
@ 2026-07-13 22:22 ` Pierrick Bouvier
0 siblings, 0 replies; 37+ messages in thread
From: Pierrick Bouvier @ 2026-07-13 22:22 UTC (permalink / raw)
To: Matheus Tavares Bernardino, qemu-devel
Cc: brian.cain, marco.liebel, philmd, ale, anjo,
Matheus Tavares Bernardino
On 7/13/2026 1:07 PM, Matheus Tavares Bernardino wrote:
> From: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
>
> Baremetal Hexagon programs invoke SYS_COREDUMP (0xCD)
> through semihosting to dump CPU state on a fatal exception.
> Implement the handler to decode the SSR cause field and
> print the full register file, matching hexagon-sim behavior.
>
> Signed-off-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> ---
> target/hexagon/internal.h | 1 +
> target/hexagon/cpu.c | 2 +-
> target/hexagon/hexswi.c | 143 ++++++++++++++++++++++++++++++++++++++
> 3 files changed, 145 insertions(+), 1 deletion(-)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 12/14] target/hexagon: Add an errno mapping
2026-07-13 20:07 ` [PATCH 12/14] target/hexagon: Add an errno mapping Matheus Tavares Bernardino
@ 2026-07-13 22:23 ` Pierrick Bouvier
0 siblings, 0 replies; 37+ messages in thread
From: Pierrick Bouvier @ 2026-07-13 22:23 UTC (permalink / raw)
To: Matheus Tavares Bernardino, qemu-devel
Cc: brian.cain, marco.liebel, philmd, ale, anjo
On 7/13/2026 1:07 PM, Matheus Tavares Bernardino wrote:
> 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>
> Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
> ---
> target/hexagon/hexswi.c | 81 +++++++++++++++++++++++++++++++++--------
> 1 file changed, 66 insertions(+), 15 deletions(-)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 13/14] python/machine: support routing semihosting output to the test console
2026-07-13 20:07 ` [PATCH 13/14] python/machine: support routing semihosting output to the test console Matheus Tavares Bernardino
@ 2026-07-13 22:23 ` Pierrick Bouvier
0 siblings, 0 replies; 37+ messages in thread
From: Pierrick Bouvier @ 2026-07-13 22:23 UTC (permalink / raw)
To: Matheus Tavares Bernardino, qemu-devel
Cc: brian.cain, marco.liebel, philmd, ale, anjo, John Snow,
Cleber Rosa
On 7/13/2026 1:07 PM, 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>
> 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: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 14/14] tests/functional: Add hexagon semihosting systests
2026-07-13 20:07 ` [PATCH 14/14] tests/functional: Add hexagon semihosting systests Matheus Tavares Bernardino
@ 2026-07-13 22:28 ` Pierrick Bouvier
2026-07-14 10:28 ` Matheus Tavares Bernardino
2026-07-14 8:25 ` Daniel P. Berrangé
1 sibling, 1 reply; 37+ messages in thread
From: Pierrick Bouvier @ 2026-07-13 22:28 UTC (permalink / raw)
To: Matheus Tavares Bernardino, qemu-devel
Cc: brian.cain, marco.liebel, philmd, ale, anjo, Thomas Huth,
Philippe Mathieu-Daudé, Daniel P. Berrangé
On 7/13/2026 1:07 PM, Matheus Tavares Bernardino wrote:
> From: Brian Cain <brian.cain@oss.qualcomm.com>
>
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
> ---
> tests/functional/hexagon/meson.build | 9 ++
> tests/functional/hexagon/test_systests.py | 133 ++++++++++++++++++++++
> tests/functional/meson.build | 1 +
> 3 files changed, 143 insertions(+)
> create mode 100644 tests/functional/hexagon/meson.build
> create mode 100644 tests/functional/hexagon/test_systests.py
>
> diff --git a/tests/functional/hexagon/meson.build b/tests/functional/hexagon/meson.build
> new file mode 100644
> index 00000000000..6cd684b0df7
> --- /dev/null
> +++ b/tests/functional/hexagon/meson.build
> @@ -0,0 +1,9 @@
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +
> +test_hexagon_timeouts = {
> + 'systests': 180,
> +}
> +
> +tests_hexagon_system_thorough = [
> + 'systests',
> +]
> diff --git a/tests/functional/hexagon/test_systests.py b/tests/functional/hexagon/test_systests.py
> new file mode 100644
> index 00000000000..b20b9fc56cc
> --- /dev/null
> +++ b/tests/functional/hexagon/test_systests.py
> @@ -0,0 +1,133 @@
> +#!/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 = os.path.join(
> + "systests_standalone_package",
> + "StandaloneSysTests_6.4.0.2_v68",
> + "bin",
> +)
> +
> +
> +class SysTestsStandaloneTests(QemuSystemTest):
> + SYSTEST_TIMEOUT_SEC = 30
> +
> + ASSET_TARBALL = Asset(
> + "https://github.com/qualcomm/qemu-hexagon-testing/releases/download/v0.2.9/systests_standalone.tar.gz",
> + "db961ea3fcc389b478b3d5c2f3bac60bec87e7f3d7efef5e58a9ae8ee78d0e40",
> + )
> +
> + def setUp(self):
> + super().setUp()
> + self.archive_extract(self.ASSET_TARBALL)
> + self.bin_dir = os.path.join(self.workdir, _TARBALL_BIN_PATH)
> + self._orig_cwd = os.getcwd()
> + os.chdir(self.workdir)
> + self.addCleanup(os.chdir, self._orig_cwd)
> +
> + def tearDown(self):
> + if hasattr(self, "_orig_cwd"):
> + os.chdir(self._orig_cwd)
> + super().tearDown()
> +
> + def binary(self, name):
> + """Return the full path to binary *name* inside bin_dir."""
> + return os.path.join(self.bin_dir, name)
> +
> + 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").
> + """
We could check self.binary(binary_name) exists to provide a useful error
message.
> + self.set_machine(machine)
> + self.set_vm_arg("-display", "none")
> + self.set_vm_arg("-kernel", self.binary(binary_name))
> + for flag, value in zip(extra_args[::2], extra_args[1::2]):
> + self.set_vm_arg(flag, value)
> + self.vm.launch()
> + self.vm.wait(timeout=60.0)
> + self.assertEqual(self.vm.exitcode(), 0,
> + f"Test {binary_name} exited with "
> + f"code {self.vm.exitcode()}, expected 0")
> +
> + def run_console_pattern(self, binary_name, pattern, *extra_args,
> + machine="V66G_1024"):
> + """Launch *binary_name* and wait for *pattern* on the semihosting console.
> +
> + :param binary_name: name of the binary inside bin_dir.
> + :param pattern: string pattern to wait for via wait_for_console_pattern.
> + :param extra_args: optional pairs of (flag, value) strings passed
> + to set_vm_arg(), e.g. ('-append', 'myarg').
> + :param machine: QEMU machine type (default "V66G_1024").
> + """
> + self.set_machine(machine)
> + self.set_vm_arg("-display", "none")
> + self.set_vm_arg("-kernel", self.binary(binary_name))
> + for flag, value in zip(extra_args[::2], extra_args[1::2]):
> + self.set_vm_arg(flag, value)
> + self.vm.set_console(semihosting=True)
> + self.vm.launch()
> + try:
> + wait_for_console_pattern(self, pattern)
> + finally:
> + self.vm.kill()
> +
> + def test_fopen(self):
> + """fopen reads a file passed via --append and verifies its contents."""
> + with open(os.path.join(self.workdir, "dummy.so"), "w") as f:
> + f.write("valid\n")
> + self.run_exit_zero("fopen", "-append", "dummy.so")
> +
> + def test_ftrunc(self):
> + """ftrunc truncates _testfile_ftrunc from 6 bytes to 1 byte."""
> + ftrunc_path = os.path.join(self.workdir, "_testfile_ftrunc")
> + with open(ftrunc_path, "w") as f:
> + f.write("valid\n")
> + # Sleep 1 s so mtime change is observable
> + time.sleep(1)
> + self.run_exit_zero("ftrunc")
> + self.assertEqual(
> + os.path.getsize(ftrunc_path),
> + 1,
> + "_testfile_ftrunc should be 1 byte after ftrunc",
> + )
> +
> + def test_dirent(self):
> + """dirent lists a directory passed via --append; output must be
> + '. .. fileA fileB'."""
> + dirent_dir = os.path.join(self.workdir, "_dirent_testdir")
> + os.makedirs(dirent_dir, exist_ok=True)
> + open(os.path.join(dirent_dir, "fileA"), "w").close()
> + open(os.path.join(dirent_dir, "fileB"), "w").close()
> + self.run_console_pattern(
> + "dirent", ". .. fileA fileB", "-append", "_dirent_testdir"
> + )
> +
> + def test_access(self):
> + """access checks R_OK|W_OK on _testfile_access."""
> + with open(os.path.join(self.workdir, "_testfile_access"), "w") as f:
> + f.write("valid\n")
> + self.run_exit_zero("access")
> +
> + def test_semihost(self):
> + semihost_dir = os.path.join(self.workdir, "_semihost_dir")
> + os.makedirs(semihost_dir, exist_ok=True)
> + open(os.path.join(semihost_dir, "fileA"), "w").close()
> + open(os.path.join(semihost_dir, "fileB"), "w").close()
> + self.run_console_pattern("semihost", "PASS", "-append", "arg1", "arg2")
> +
> +if __name__ == "__main__":
> + QemuSystemTest.main()
> diff --git a/tests/functional/meson.build b/tests/functional/meson.build
> index c158197c4b7..c7362dd00ef 100644
> --- a/tests/functional/meson.build
> +++ b/tests/functional/meson.build
> @@ -14,6 +14,7 @@ subdir('aarch64')
> subdir('alpha')
> subdir('arm')
> subdir('avr')
> +subdir('hexagon')
> subdir('hppa')
> subdir('i386')
> subdir('loongarch64')
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 11/14] target/hexagon: add OPEN/READ/CLOSE_DIR semihosting operations
2026-07-13 20:07 ` [PATCH 11/14] target/hexagon: add OPEN/READ/CLOSE_DIR semihosting operations Matheus Tavares Bernardino
@ 2026-07-13 22:33 ` Pierrick Bouvier
0 siblings, 0 replies; 37+ messages in thread
From: Pierrick Bouvier @ 2026-07-13 22:33 UTC (permalink / raw)
To: Matheus Tavares Bernardino, qemu-devel
Cc: brian.cain, marco.liebel, philmd, ale, anjo,
Matheus Tavares Bernardino
On 7/13/2026 1:07 PM, Matheus Tavares Bernardino wrote:
> From: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
>
> Baremetal Hexagon programs use semihosting to enumerate host
> directories via OPENDIR, READDIR, and CLOSEDIR calls. Track
> open directory handles per-CPU in a GList so that guest
> index values map back to host DIR pointers across calls.
>
> Signed-off-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> ---
> target/hexagon/cpu.h | 1 +
> hw/hexagon/hexagon_dsp.c | 5 +++
> hw/hexagon/virt.c | 5 +++
> target/hexagon/hexswi.c | 79 ++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 90 insertions(+)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 14/14] tests/functional: Add hexagon semihosting systests
2026-07-13 20:07 ` [PATCH 14/14] tests/functional: Add hexagon semihosting systests Matheus Tavares Bernardino
2026-07-13 22:28 ` Pierrick Bouvier
@ 2026-07-14 8:25 ` Daniel P. Berrangé
1 sibling, 0 replies; 37+ messages in thread
From: Daniel P. Berrangé @ 2026-07-14 8:25 UTC (permalink / raw)
To: Matheus Tavares Bernardino
Cc: qemu-devel, brian.cain, pierrick.bouvier, marco.liebel, philmd,
ale, anjo, Thomas Huth, Philippe Mathieu-Daudé
On Mon, Jul 13, 2026 at 01:07:22PM -0700, Matheus Tavares Bernardino wrote:
> From: Brian Cain <brian.cain@oss.qualcomm.com>
>
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
> ---
> tests/functional/hexagon/meson.build | 9 ++
> tests/functional/hexagon/test_systests.py | 133 ++++++++++++++++++++++
> tests/functional/meson.build | 1 +
> 3 files changed, 143 insertions(+)
> create mode 100644 tests/functional/hexagon/meson.build
> create mode 100644 tests/functional/hexagon/test_systests.py
>
> diff --git a/tests/functional/hexagon/meson.build b/tests/functional/hexagon/meson.build
> new file mode 100644
> index 00000000000..6cd684b0df7
> --- /dev/null
> +++ b/tests/functional/hexagon/meson.build
> @@ -0,0 +1,9 @@
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +
> +test_hexagon_timeouts = {
> + 'systests': 180,
> +}
> +
> +tests_hexagon_system_thorough = [
> + 'systests',
> +]
> diff --git a/tests/functional/hexagon/test_systests.py b/tests/functional/hexagon/test_systests.py
> new file mode 100644
> index 00000000000..b20b9fc56cc
Test files should have execute permissions.
> --- /dev/null
> +++ b/tests/functional/hexagon/test_systests.py
> @@ -0,0 +1,133 @@
> +#!/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 = os.path.join(
> + "systests_standalone_package",
> + "StandaloneSysTests_6.4.0.2_v68",
> + "bin",
> +)
Don't use os.path.join to refer to files needed by the test
suite - always use one of the helper methods on the QemuBaseTest
class....
> +
> +
> +class SysTestsStandaloneTests(QemuSystemTest):
> + SYSTEST_TIMEOUT_SEC = 30
> +
> + ASSET_TARBALL = Asset(
> + "https://github.com/qualcomm/qemu-hexagon-testing/releases/download/v0.2.9/systests_standalone.tar.gz",
> + "db961ea3fcc389b478b3d5c2f3bac60bec87e7f3d7efef5e58a9ae8ee78d0e40",
> + )
> +
> + def setUp(self):
> + super().setUp()
> + self.archive_extract(self.ASSET_TARBALL)
> + self.bin_dir = os.path.join(self.workdir, _TARBALL_BIN_PATH)
...so also skip this...
> + self._orig_cwd = os.getcwd()
> + os.chdir(self.workdir)
> + self.addCleanup(os.chdir, self._orig_cwd)
Don't change directory during tests - use properly qualified paths
to files.
> +
> + def tearDown(self):
> + if hasattr(self, "_orig_cwd"):
> + os.chdir(self._orig_cwd)
> + super().tearDown()
> +
> + def binary(self, name):
> + """Return the full path to binary *name* inside bin_dir."""
> + return os.path.join(self.bin_dir, name)
This should be just:
return self.scratch_file("systests_standalone_package",
"StandaloneSysTests_6.4.0.2_v68", "bin", name)
> +
> + def run_exit_zero(self, binary_name, *extra_args, machine="V66G_1024"):
> + """Launch *binary_name* and assert it exits with code 0.
> +
> + :param binary_name: name of the binary inside bin_dir.
> + :param extra_args: optional pairs of (flag, value) strings passed
> + to set_vm_arg(), e.g. ('-append', 'myarg').
> + :param machine: QEMU machine type (default "V66G_1024").
> + """
> + self.set_machine(machine)
> + self.set_vm_arg("-display", "none")
> + self.set_vm_arg("-kernel", self.binary(binary_name))
> + for flag, value in zip(extra_args[::2], extra_args[1::2]):
> + self.set_vm_arg(flag, value)
> + self.vm.launch()
> + self.vm.wait(timeout=60.0)
> + self.assertEqual(self.vm.exitcode(), 0,
> + f"Test {binary_name} exited with "
> + f"code {self.vm.exitcode()}, expected 0")
> +
> + def run_console_pattern(self, binary_name, pattern, *extra_args,
> + machine="V66G_1024"):
> + """Launch *binary_name* and wait for *pattern* on the semihosting console.
> +
> + :param binary_name: name of the binary inside bin_dir.
> + :param pattern: string pattern to wait for via wait_for_console_pattern.
> + :param extra_args: optional pairs of (flag, value) strings passed
> + to set_vm_arg(), e.g. ('-append', 'myarg').
> + :param machine: QEMU machine type (default "V66G_1024").
> + """
> + self.set_machine(machine)
> + self.set_vm_arg("-display", "none")
> + self.set_vm_arg("-kernel", self.binary(binary_name))
> + for flag, value in zip(extra_args[::2], extra_args[1::2]):
> + self.set_vm_arg(flag, value)
> + self.vm.set_console(semihosting=True)
> + self.vm.launch()
> + try:
> + wait_for_console_pattern(self, pattern)
> + finally:
> + self.vm.kill()
> +
> + def test_fopen(self):
> + """fopen reads a file passed via --append and verifies its contents."""
> + with open(os.path.join(self.workdir, "dummy.so"), "w") as f:
self.scratch_file("dummy.so")
> + f.write("valid\n")
> + self.run_exit_zero("fopen", "-append", "dummy.so")
How is this working ? You've created a file dummy.so on the host OS,
and you're passing a filename "dummy.so" to -append which is a kernel
arg. The implication is the kenrel opens this file, but how is the guest
kernel accessing the file from the host ?!?!??
> +
> + def test_ftrunc(self):
> + """ftrunc truncates _testfile_ftrunc from 6 bytes to 1 byte."""
> + ftrunc_path = os.path.join(self.workdir, "_testfile_ftrunc")
self.scratch_file("_testfile_ftrunc")
> + with open(ftrunc_path, "w") as f:
> + f.write("valid\n")
> + # Sleep 1 s so mtime change is observable
> + time.sleep(1)
> + self.run_exit_zero("ftrunc")
> + self.assertEqual(
> + os.path.getsize(ftrunc_path),
> + 1,
> + "_testfile_ftrunc should be 1 byte after ftrunc",
> + )
> +
> + def test_dirent(self):
> + """dirent lists a directory passed via --append; output must be
> + '. .. fileA fileB'."""
> + dirent_dir = os.path.join(self.workdir, "_dirent_testdir")
self.scratch_file("_dirent_testdir")
> + os.makedirs(dirent_dir, exist_ok=True)
> + open(os.path.join(dirent_dir, "fileA"), "w").close()
> + open(os.path.join(dirent_dir, "fileB"), "w").close()
self.scratch_file("_dirent_testdir", "fileA")
> + self.run_console_pattern(
> + "dirent", ". .. fileA fileB", "-append", "_dirent_testdir"
Again I'm wondering how the guest OS accesses _dirent_testdir which
is a location on the host OS ?
> + )
> +
> + def test_access(self):
> + """access checks R_OK|W_OK on _testfile_access."""
> + with open(os.path.join(self.workdir, "_testfile_access"), "w") as f:
> + f.write("valid\n")
self.scratch_file("_testfile_access")
> + self.run_exit_zero("access")
> +
> + def test_semihost(self):
> + semihost_dir = os.path.join(self.workdir, "_semihost_dir")
> + os.makedirs(semihost_dir, exist_ok=True)
> + open(os.path.join(semihost_dir, "fileA"), "w").close()
> + open(os.path.join(semihost_dir, "fileB"), "w").close()
The intermediate dir feels redunddant - why not just create fileA & fileB
directly ? ie
self.scratch_file("fileA")
self.scratch_file("fileB")
> + self.run_console_pattern("semihost", "PASS", "-append", "arg1", "arg2")
> +
> +if __name__ == "__main__":
> + QemuSystemTest.main()
> diff --git a/tests/functional/meson.build b/tests/functional/meson.build
> index c158197c4b7..c7362dd00ef 100644
> --- a/tests/functional/meson.build
> +++ b/tests/functional/meson.build
> @@ -14,6 +14,7 @@ subdir('aarch64')
> subdir('alpha')
> subdir('arm')
> subdir('avr')
> +subdir('hexagon')
> subdir('hppa')
> subdir('i386')
> subdir('loongarch64')
> --
> 2.37.2
>
With regards,
Daniel
--
|: https://berrange.com ~~ https://hachyderm.io/@berrange :|
|: https://libvirt.org ~~ https://entangle-photo.org :|
|: https://pixelfed.art/berrange ~~ https://fstop138.berrange.com :|
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 05/14] semihosting: add callback to set error
2026-07-13 20:07 ` [PATCH 05/14] semihosting: add callback to set error Matheus Tavares Bernardino
2026-07-13 22:01 ` Pierrick Bouvier
@ 2026-07-14 9:50 ` Daniel Henrique Barboza
2026-07-14 10:00 ` Matheus Tavares Bernardino
1 sibling, 1 reply; 37+ messages in thread
From: Daniel Henrique Barboza @ 2026-07-14 9:50 UTC (permalink / raw)
To: Matheus Tavares Bernardino, qemu-devel
Cc: brian.cain, pierrick.bouvier, marco.liebel, philmd, ale, anjo,
Alex Bennée, Peter Maydell, Palmer Dabbelt, Alistair Francis,
Weiwei Li, Liu Zhiwei, Chao Liu, qemu-arm, qemu-riscv
On 7/13/2026 5:07 PM, Matheus Tavares Bernardino wrote:
> This is currently unused by existing semihosting targets, but it will be
> used by hexagon.
>
> Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> ---
I suggest making it patch 06 in the series, right before you use in patch 7. You
can even mention "next patch will use it" in the commit msg for extra clarity.
As for the code:
Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
> include/semihosting/common-semi.h | 1 +
> semihosting/arm-compat-semi.c | 1 +
> target/arm/common-semi-target.c | 4 ++++
> target/riscv/common-semi-target.c | 4 ++++
> 4 files changed, 10 insertions(+)
>
> diff --git a/include/semihosting/common-semi.h b/include/semihosting/common-semi.h
> index aa511a46f42..a11905ef4ef 100644
> --- a/include/semihosting/common-semi.h
> +++ b/include/semihosting/common-semi.h
> @@ -37,6 +37,7 @@
> void do_common_semihosting(CPUState *cs);
> uint64_t common_semi_arg(CPUState *cs, int argno);
> void common_semi_set_ret(CPUState *cs, uint64_t ret);
> +void common_semi_set_err(CPUState *cs, int err);
> bool is_64bit_semihosting(CPUArchState *env);
> bool common_semi_sys_exit_is_extended(CPUState *cs);
> uint64_t common_semi_stack_bottom(CPUState *cs);
> diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
> index 5e5f181b908..c54753f696f 100644
> --- a/semihosting/arm-compat-semi.c
> +++ b/semihosting/arm-compat-semi.c
> @@ -237,6 +237,7 @@ static void common_semi_cb(CPUState *cs, uint64_t ret, int err)
> ts->swi_errno = err;
> #else
> syscall_err = err;
> + common_semi_set_err(cs, err);
> #endif
> }
> common_semi_set_ret(cs, ret);
> diff --git a/target/arm/common-semi-target.c b/target/arm/common-semi-target.c
> index 2b77ce9c17b..38d52deb3d6 100644
> --- a/target/arm/common-semi-target.c
> +++ b/target/arm/common-semi-target.c
> @@ -34,6 +34,10 @@ void common_semi_set_ret(CPUState *cs, uint64_t ret)
> }
> }
>
> +void common_semi_set_err(CPUState *cs, int err)
> +{
> +}
> +
> bool common_semi_sys_exit_is_extended(CPUState *cs)
> {
> return is_a64(cpu_env(cs));
> diff --git a/target/riscv/common-semi-target.c b/target/riscv/common-semi-target.c
> index aeaeb88d536..38a00e160c3 100644
> --- a/target/riscv/common-semi-target.c
> +++ b/target/riscv/common-semi-target.c
> @@ -26,6 +26,10 @@ void common_semi_set_ret(CPUState *cs, uint64_t ret)
> env->gpr[xA0] = ret;
> }
>
> +void common_semi_set_err(CPUState *cs, int err)
> +{
> +}
> +
> bool is_64bit_semihosting(CPUArchState *env)
> {
> return riscv_cpu_mxl(env) != MXL_RV32;
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 05/14] semihosting: add callback to set error
2026-07-14 9:50 ` Daniel Henrique Barboza
@ 2026-07-14 10:00 ` Matheus Tavares Bernardino
0 siblings, 0 replies; 37+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-14 10:00 UTC (permalink / raw)
To: daniel.barboza
Cc: matheus.bernardino, qemu-devel, brian.cain, pierrick.bouvier,
marco.liebel, philmd, ale, anjo, alex.bennee, peter.maydell,
palmer, alistair.francis, liwei1518, zhiwei_liu, chao.liu,
qemu-arm, qemu-riscv
On Tue, 14 Jul 2026 06:50:19 -0300 Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> wrote:
>
> On 7/13/2026 5:07 PM, Matheus Tavares Bernardino wrote:
> > This is currently unused by existing semihosting targets, but it will be
> > used by hexagon.
> >
> > Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
> > Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> > ---
>
> I suggest making it patch 06 in the series, right before you use in patch 7. You
> can even mention "next patch will use it" in the commit msg for extra clarity.
Good idea, will do. Thanks
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 09/14] target/hexagon: add main arch-specific semihosting operations
2026-07-13 22:20 ` Pierrick Bouvier
@ 2026-07-14 10:10 ` Matheus Tavares Bernardino
0 siblings, 0 replies; 37+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-14 10:10 UTC (permalink / raw)
To: pierrick.bouvier
Cc: matheus.bernardino, qemu-devel, brian.cain, marco.liebel, philmd,
ale, anjo, alex.bennee
On Mon, 13 Jul 2026 15:20:29 -0700 Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com> wrote:
>
> On 7/13/2026 1:07 PM, Matheus Tavares Bernardino wrote:
> > + target_ulong physicalFilenameAddr;
>
> style: physical_filename_addr;
> [...]
> > + static const unsigned int mode_table[] = {
> [...]
> Better to extract this with a static const, and a useful name.
> angel_to_host_filemode_table.
> [...]
> > /* convert ARM ANGEL filemode into host filemode */
> > + if (filemode < 14) {
>
> Also, compare to sizeof table introduced, or define a constant.
> ANGEL_FILEMODE_MAX = 13.
> [...]
> > + /*
> > + * Hexagon's SYS_ISTTY is a bit different than arm's: we do not return -1
> > + * on error, neither errno. So we override with out own implementation.
> > + */
>
> s/out/our
> [...]
> > + /*
> > + * This must match the caller's definition, it would be in the
> > + * caller's angel.h or equivalent header.
> > + */
>
> It would be great to move this definition out of this function also.
Thanks, Pierrick! I'll apply all comments.
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 07/14] target/hexagon: add semihosting support
2026-07-13 22:11 ` Pierrick Bouvier
@ 2026-07-14 10:13 ` Matheus Tavares Bernardino
0 siblings, 0 replies; 37+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-14 10:13 UTC (permalink / raw)
To: pierrick.bouvier
Cc: matheus.bernardino, qemu-devel, brian.cain, marco.liebel, philmd,
ale, anjo, quic_mathbern, pbonzini
On Mon, 13 Jul 2026 15:11:18 -0700 Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com> wrote:
>
> On 7/13/2026 1:07 PM, Matheus Tavares Bernardino wrote:
> > From: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
> >
> > Baremetal Hexagon programs use trap0 #0 to invoke
> > semihosting calls for I/O and process control. Wire up the
> > arm-compatible semihosting framework for softmmu by enabling
> > CONFIG_ARM_COMPATIBLE_SEMIHOSTING and routing trap0 to the
> > semihosting handler.
> >
> > Signed-off-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
> > Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> > ---
> > configs/targets/hexagon-softmmu.mak | 2 +
> > hw/hexagon/hexagon_dsp.c | 2 +
> > target/hexagon/common-semi-target.c | 51 +++++++++
> > target/hexagon/hexswi.c | 164 +++++++++++++++++++++++++++-
> > hw/hexagon/Kconfig | 1 +
> > qemu-options.hx | 8 +-
> > target/hexagon/meson.build | 3 +
> > 7 files changed, 224 insertions(+), 7 deletions(-)
> > create mode 100644 target/hexagon/common-semi-target.c
> >
>
> ...
>
> > +static void sim_handle_trap0(CPUHexagonState *env)
> > +{
> > + target_ulong what_swi, swi_info;
> > + G_GNUC_UNUSED uintptr_t retaddr = 0;
>
> leftover?
Actually, this is used in the next commit. Let me add move it.
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 03/14] target/hexagon: add aux functions for guest mem load/store
2026-07-13 21:58 ` Pierrick Bouvier
@ 2026-07-14 10:17 ` Matheus Tavares Bernardino
0 siblings, 0 replies; 37+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-14 10:17 UTC (permalink / raw)
To: pierrick.bouvier
Cc: matheus.bernardino, qemu-devel, brian.cain, marco.liebel, philmd,
ale, anjo, quic_mathbern
On Mon, 13 Jul 2026 14:58:46 -0700 Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com> wrote:
>
> On 7/13/2026 1:07 PM, Matheus Tavares Bernardino wrote:
> >
> > +
> > +void hexagon_touch_memory(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);
> > + }
> > +}
> > +
>
> Name could be misleading, I would be expectng to see a read/write
> sequence in each page instead of just reading.
> Maybe hexagon_peek_memory_range?
Good call, will do.
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 14/14] tests/functional: Add hexagon semihosting systests
2026-07-13 22:28 ` Pierrick Bouvier
@ 2026-07-14 10:28 ` Matheus Tavares Bernardino
0 siblings, 0 replies; 37+ messages in thread
From: Matheus Tavares Bernardino @ 2026-07-14 10:28 UTC (permalink / raw)
To: pierrick.bouvier
Cc: matheus.bernardino, qemu-devel, brian.cain, marco.liebel, philmd,
ale, anjo, th.huth+qemu, philmd, berrange
On Mon, 13 Jul 2026 15:28:46 -0700 Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com> wrote:
>
> On 7/13/2026 1:07 PM, Matheus Tavares Bernardino wrote:
> > From: Brian Cain <brian.cain@oss.qualcomm.com>
> >
> > Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> > Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
> > ---
> > tests/functional/hexagon/meson.build | 9 ++
> > tests/functional/hexagon/test_systests.py | 133 ++++++++++++++++++++++
> > tests/functional/meson.build | 1 +
> > 3 files changed, 143 insertions(+)
> > create mode 100644 tests/functional/hexagon/meson.build
> > create mode 100644 tests/functional/hexagon/test_systests.py
> >
> > diff --git a/tests/functional/hexagon/meson.build b/tests/functional/hexagon/meson.build
> > new file mode 100644
> > index 00000000000..6cd684b0df7
> > --- /dev/null
> > +++ b/tests/functional/hexagon/meson.build
> > @@ -0,0 +1,9 @@
> > +# SPDX-License-Identifier: GPL-2.0-or-later
> > +
> > +test_hexagon_timeouts = {
> > + 'systests': 180,
> > +}
> > +
> > +tests_hexagon_system_thorough = [
> > + 'systests',
> > +]
> > diff --git a/tests/functional/hexagon/test_systests.py b/tests/functional/hexagon/test_systests.py
> > new file mode 100644
> > index 00000000000..b20b9fc56cc
> > --- /dev/null
> > +++ b/tests/functional/hexagon/test_systests.py
> > @@ -0,0 +1,133 @@
> > +#!/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 = os.path.join(
> > + "systests_standalone_package",
> > + "StandaloneSysTests_6.4.0.2_v68",
> > + "bin",
> > +)
> > +
> > +
> > +class SysTestsStandaloneTests(QemuSystemTest):
> > + SYSTEST_TIMEOUT_SEC = 30
> > +
> > + ASSET_TARBALL = Asset(
> > + "https://github.com/qualcomm/qemu-hexagon-testing/releases/download/v0.2.9/systests_standalone.tar.gz",
> > + "db961ea3fcc389b478b3d5c2f3bac60bec87e7f3d7efef5e58a9ae8ee78d0e40",
> > + )
> > +
> > + def setUp(self):
> > + super().setUp()
> > + self.archive_extract(self.ASSET_TARBALL)
> > + self.bin_dir = os.path.join(self.workdir, _TARBALL_BIN_PATH)
> > + self._orig_cwd = os.getcwd()
> > + os.chdir(self.workdir)
> > + self.addCleanup(os.chdir, self._orig_cwd)
> > +
> > + def tearDown(self):
> > + if hasattr(self, "_orig_cwd"):
> > + os.chdir(self._orig_cwd)
> > + super().tearDown()
> > +
> > + def binary(self, name):
> > + """Return the full path to binary *name* inside bin_dir."""
> > + return os.path.join(self.bin_dir, name)
> > +
> > + 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").
> > + """
>
>
> We could check self.binary(binary_name) exists to provide a useful error
> message.
Ok, good idea. I'll add the following:
diff --git a/tests/functional/hexagon/test_systests.py b/tests/functional/hexagon/test_systests.py
index b20b9fc56cc..692ec5ad2d5 100644
--- a/tests/functional/hexagon/test_systests.py
+++ b/tests/functional/hexagon/test_systests.py
@@ -42,7 +42,9 @@ def tearDown(self):
def binary(self, name):
"""Return the full path to binary *name* inside bin_dir."""
- return os.path.join(self.bin_dir, name)
+ path = os.path.join(self.bin_dir, 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
^ permalink raw reply related [flat|nested] 37+ messages in thread
end of thread, other threads:[~2026-07-14 10:29 UTC | newest]
Thread overview: 37+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-13 20:07 [PATCH 00/14] hexagon: add semihosting support Matheus Tavares Bernardino
2026-07-13 20:07 ` [PATCH 01/14] target/hexagon: fix get_phys_addr_debug with in-page offset Matheus Tavares Bernardino
2026-07-13 21:41 ` Pierrick Bouvier
2026-07-13 20:07 ` [PATCH 02/14] target/hexagon: fix PC advancement for non-COF TB terminators Matheus Tavares Bernardino
2026-07-13 21:53 ` Pierrick Bouvier
2026-07-13 20:07 ` [PATCH 03/14] target/hexagon: add aux functions for guest mem load/store Matheus Tavares Bernardino
2026-07-13 21:58 ` Pierrick Bouvier
2026-07-14 10:17 ` Matheus Tavares Bernardino
2026-07-13 20:07 ` [PATCH 04/14] hexagon: cpu_helper: add reg reading/writing helpers Matheus Tavares Bernardino
2026-07-13 22:00 ` Pierrick Bouvier
2026-07-13 20:07 ` [PATCH 05/14] semihosting: add callback to set error Matheus Tavares Bernardino
2026-07-13 22:01 ` Pierrick Bouvier
2026-07-14 9:50 ` Daniel Henrique Barboza
2026-07-14 10:00 ` Matheus Tavares Bernardino
2026-07-13 20:07 ` [PATCH 06/14] semihosting: add APIs for chardev-aware guest fd routing Matheus Tavares Bernardino
2026-07-13 22:04 ` Pierrick Bouvier
2026-07-13 20:07 ` [PATCH 07/14] target/hexagon: add semihosting support Matheus Tavares Bernardino
2026-07-13 22:11 ` Pierrick Bouvier
2026-07-14 10:13 ` Matheus Tavares Bernardino
2026-07-13 20:07 ` [PATCH 08/14] semihosting: add ftruncate helper (to be used for hexagon) Matheus Tavares Bernardino
2026-07-13 22:12 ` Pierrick Bouvier
2026-07-13 20:07 ` [PATCH 09/14] target/hexagon: add main arch-specific semihosting operations Matheus Tavares Bernardino
2026-07-13 22:20 ` Pierrick Bouvier
2026-07-14 10:10 ` Matheus Tavares Bernardino
2026-07-13 20:07 ` [PATCH 10/14] target/hexagon: add COREDUMP semihosting operation Matheus Tavares Bernardino
2026-07-13 22:22 ` Pierrick Bouvier
2026-07-13 20:07 ` [PATCH 11/14] target/hexagon: add OPEN/READ/CLOSE_DIR semihosting operations Matheus Tavares Bernardino
2026-07-13 22:33 ` Pierrick Bouvier
2026-07-13 20:07 ` [PATCH 12/14] target/hexagon: Add an errno mapping Matheus Tavares Bernardino
2026-07-13 22:23 ` Pierrick Bouvier
2026-07-13 20:07 ` [PATCH 13/14] python/machine: support routing semihosting output to the test console Matheus Tavares Bernardino
2026-07-13 22:23 ` Pierrick Bouvier
2026-07-13 20:07 ` [PATCH 14/14] tests/functional: Add hexagon semihosting systests Matheus Tavares Bernardino
2026-07-13 22:28 ` Pierrick Bouvier
2026-07-14 10:28 ` Matheus Tavares Bernardino
2026-07-14 8:25 ` Daniel P. Berrangé
2026-07-13 21:51 ` [PATCH 00/14] hexagon: add semihosting support Pierrick Bouvier
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.