This series adds semihosting support to hexagon system emulation, together with functional tests for the added operations.
The Hexagon semihosting spec can be found at: https://docs.qualcomm.com/doc/80-N2040-101_102648/topic/semihosting-specification.html v1: https://lore.kernel.org/qemu-devel/[email protected]/ v2: https://lore.kernel.org/qemu-devel/[email protected]/T/#m9e966877cda81c5661838fedadf4e69bd912cbb5 v3: https://lore.kernel.org/qemu-devel/[email protected]/ Changes in v4: - Added patches 1 and 2: a couple hexagon fixes for big-endian hosts - Patch 3: fix unaligned pc reporting on linux-user mode - Patch 5: fix big-endian issues - Patch 8 and 11: drop arch_[gs]et_(thread|system)_reg() - Patch 10: avoid OS-specific ifdefs and fixes for big-endian - Patch 12: define target errnos in a more readable way - Patch 14: drop unuseful code comments Changes in v3: - Reworded semihosting section at Hexagon docs - Rebased, added Reviewed-by's, dropped already merged patch Changes in v2: - Added patch 1, a fix for an existing bug that appeared with the new test semantics from the last patch. - Patch 3: s/hexagon_touch_memory/hexagon_peek_memory_range/ - Patch 7: * Add semihosting spec link to docs * Fixed HEX_SYS_EXCEPTION - Patch 10: * Moved tables to static definition * Fixed compilation for Windows - Dropped patch 11 (OPEN/READ/CLOSE_DIR support): for now we don't have dirent semantics for Windows, so leave these ops to a followup series. - Patch 14: * Update test version * Don't change directory * Don't use os.path, use scratch_file Brian Cain (4): semihosting: add APIs for chardev-aware guest fd routing target/hexagon: Add an errno mapping python/machine: support routing semihosting output to the test console tests/functional: Add hexagon semihosting systests Matheus Tavares Bernardino (10): disas/hexagon: honour target byte order when printing instructions target/hexagon: fix store-conditional on big-endian hosts target/hexagon: fix improper assign of cause code to exception index target/hexagon: fix PC advancement for non-COF TB terminators target/hexagon: add aux functions for guest mem load/store semihosting: add callback to set error target/hexagon: add semihosting support semihosting: add ftruncate helper (to be used for hexagon) target/hexagon: add main arch-specific semihosting operations target/hexagon: add COREDUMP semihosting operation configs/targets/hexagon-softmmu.mak | 2 + disas/hexagon.c | 6 +- docs/system/target-hexagon.rst | 8 +- hw/hexagon/Kconfig | 1 + hw/hexagon/hexagon_dsp.c | 2 + include/semihosting/common-semi.h | 2 + include/semihosting/console.h | 9 + include/semihosting/guestfd.h | 9 + include/semihosting/syscalls.h | 2 + linux-user/hexagon/cpu_loop.c | 5 +- python/qemu/machine/machine.py | 10 +- qemu-options.hx | 8 +- semihosting/arm-compat-semi.c | 3 +- semihosting/console.c | 5 + semihosting/guestfd.c | 8 + semihosting/syscalls.c | 29 + target/arm/common-semi-target.c | 4 + target/hexagon/common-semi-target.c | 51 ++ target/hexagon/cpu.c | 5 +- target/hexagon/cpu_helper.c | 100 ++++ target/hexagon/cpu_helper.h | 6 + target/hexagon/genptr.c | 4 +- target/hexagon/hexswi.c | 672 +++++++++++++++++++++- target/hexagon/internal.h | 1 + target/hexagon/meson.build | 1 + target/hexagon/translate.c | 17 +- target/riscv/common-semi-target.c | 4 + tests/functional/hexagon/meson.build | 5 + tests/functional/hexagon/test_systests.py | 94 +++ 29 files changed, 1046 insertions(+), 27 deletions(-) create mode 100644 target/hexagon/common-semi-target.c create mode 100755 tests/functional/hexagon/test_systests.py Range-diff against v3: -: ---------- > 1: 16f730778f disas/hexagon: honour target byte order when printing instructions -: ---------- > 2: 4fc8afeddf target/hexagon: fix store-conditional on big-endian hosts 1: 3f809b51ae ! 3: 5403f0e70b target/hexagon: fix improper assign of cause code to exception index @@ Commit message Reviewed-by: Pierrick Bouvier <[email protected]> Signed-off-by: Matheus Tavares Bernardino <[email protected]> + ## linux-user/hexagon/cpu_loop.c ## +@@ linux-user/hexagon/cpu_loop.c: void cpu_loop(CPUHexagonState *env) + break; + case HEX_CAUSE_MISALIGNED_LOAD: + case HEX_CAUSE_MISALIGNED_STORE: ++ case HEX_CAUSE_PC_NOT_ALIGNED: + force_sig_fault(TARGET_SIGBUS, TARGET_BUS_ADRALN, + env->gpr[HEX_REG_PC]); + break; +@@ linux-user/hexagon/cpu_loop.c: void cpu_loop(CPUHexagonState *env) + exit(EXIT_FAILURE); + } + break; +- case HEX_CAUSE_PC_NOT_ALIGNED: +- force_sig_fault(TARGET_SIGBUS, TARGET_BUS_ADRALN, +- env->gpr[HEX_REG_R31]); +- break; + case HEX_CAUSE_INVALID_PACKET: + case HEX_CAUSE_REG_WRITE_CONFLICT: + force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, + ## target/hexagon/cpu.c ## @@ target/hexagon/cpu.c: static TCGTBCPUState hexagon_get_tb_cpu_state(CPUState *cs) hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, IS_TIGHT_LOOP, 1); 2: 903af8b645 = 4: c1dad05e0a target/hexagon: fix PC advancement for non-COF TB terminators 3: 334bb76346 ! 5: a1f63c8909 target/hexagon: add aux functions for guest mem load/store @@ target/hexagon/cpu_helper.c +#ifndef CONFIG_USER_ONLY + +static bool hexagon_read_memory_small(CPUHexagonState *env, target_ulong addr, -+ int byte_count, unsigned char *dstbuf, ++ int byte_count, uint64_t *data, + int mmu_idx, uintptr_t retaddr) + { + /* handle small sizes */ + switch (byte_count) { + case 1: -+ *dstbuf = cpu_ldub_mmuidx_ra(env, addr, mmu_idx, retaddr); ++ *data = cpu_ldub_mmuidx_ra(env, addr, mmu_idx, retaddr); + return true; + + case 2: -+ if (QEMU_IS_ALIGNED(addr, 2)) { -+ *(unsigned short *)dstbuf = -+ cpu_lduw_le_mmuidx_ra(env, addr, mmu_idx, retaddr); -+ return true; -+ } -+ break; ++ *data = cpu_lduw_le_mmuidx_ra(env, addr, mmu_idx, retaddr); ++ return true; + + case 4: -+ if (QEMU_IS_ALIGNED(addr, 4)) { -+ *(uint32_t *)dstbuf = -+ cpu_ldl_le_mmuidx_ra(env, addr, mmu_idx, retaddr); -+ return true; -+ } -+ break; ++ *data = cpu_ldl_le_mmuidx_ra(env, addr, mmu_idx, retaddr); ++ return true; + + case 8: -+ if (QEMU_IS_ALIGNED(addr, 8)) { -+ *(uint64_t *)dstbuf = -+ cpu_ldq_le_mmuidx_ra(env, addr, mmu_idx, retaddr); -+ return true; -+ } -+ break; ++ *data = cpu_ldq_le_mmuidx_ra(env, addr, mmu_idx, retaddr); ++ return true; + + default: + /* larger request, handle elsewhere */ + return false; + } -+ -+ /* not aligned, copy bytes */ -+ for (int i = 0; i < byte_count; ++i) { -+ *dstbuf++ = cpu_ldub_mmuidx_ra(env, addr++, mmu_idx, retaddr); -+ } -+ return true; +} + +void hexagon_read_memory(CPUHexagonState *env, target_ulong vaddr, int size, @@ target/hexagon/cpu_helper.c + BQL_LOCK_GUARD(); + CPUState *cs = env_cpu(env); + unsigned mmu_idx = cpu_mmu_index(cs, false); -+ if (!hexagon_read_memory_small(env, vaddr, size, retptr, mmu_idx, -+ retaddr)) { ++ uint64_t data; ++ if (hexagon_read_memory_small(env, vaddr, size, &data, mmu_idx, retaddr)) { ++ stn_he_p(retptr, size, data); ++ } else { + cpu_abort(cs, "%s: ERROR: bad size = %d!\n", __func__, size); + } +} + +static bool hexagon_write_memory_small(CPUHexagonState *env, target_ulong addr, -+ int byte_count, unsigned char *srcbuf, ++ int byte_count, uint64_t data, + int mmu_idx, uintptr_t retaddr) +{ + /* handle small sizes */ + switch (byte_count) { + case 1: -+ cpu_stb_mmuidx_ra(env, addr, *srcbuf, mmu_idx, retaddr); ++ cpu_stb_mmuidx_ra(env, addr, (uint8_t)data, mmu_idx, retaddr); + return true; + + case 2: -+ if (QEMU_IS_ALIGNED(addr, 2)) { -+ cpu_stw_le_mmuidx_ra(env, addr, *(uint16_t *)srcbuf, mmu_idx, retaddr); -+ return true; -+ } -+ break; ++ cpu_stw_le_mmuidx_ra(env, addr, (uint16_t)data, mmu_idx, retaddr); ++ return true; + + case 4: -+ if (QEMU_IS_ALIGNED(addr, 4)) { -+ cpu_stl_le_mmuidx_ra(env, addr, *(uint32_t *)srcbuf, mmu_idx, retaddr); -+ return true; -+ } -+ break; ++ cpu_stl_le_mmuidx_ra(env, addr, (uint32_t)data, mmu_idx, retaddr); ++ return true; + + case 8: -+ if (QEMU_IS_ALIGNED(addr, 8)) { -+ cpu_stq_le_mmuidx_ra(env, addr, *(uint64_t *)srcbuf, mmu_idx, retaddr); -+ return true; -+ } -+ break; ++ cpu_stq_le_mmuidx_ra(env, addr, (uint64_t)data, mmu_idx, retaddr); ++ return true; + + default: + /* larger request, handle elsewhere */ + return false; + } -+ -+ /* not aligned, copy bytes */ -+ for (int i = 0; i < byte_count; ++i) { -+ cpu_stb_mmuidx_ra(env, addr++, *srcbuf++, mmu_idx, retaddr); -+ } -+ -+ return true; +} + +void hexagon_write_memory(CPUHexagonState *env, target_ulong vaddr, @@ target/hexagon/cpu_helper.c +{ + CPUState *cs = env_cpu(env); + unsigned mmu_idx = cpu_mmu_index(cs, false); -+ if (!hexagon_write_memory_small(env, vaddr, size, (unsigned char *)&data, -+ mmu_idx, retaddr)) { ++ if (!hexagon_write_memory_small(env, vaddr, size, data, mmu_idx, retaddr)) { + cpu_abort(cs, "%s: ERROR: bad size = %d!\n", __func__, size); + } +} 4: f2fc7ed466 < -: ---------- hexagon: cpu_helper: add reg reading/writing helpers 5: c8f8868aa7 = 6: 47eb2ef70d semihosting: add APIs for chardev-aware guest fd routing 6: ef17701179 = 7: a37971603c semihosting: add callback to set error 7: f0d35e6115 ! 8: 7529648c78 target/hexagon: add semihosting support @@ target/hexagon/common-semi-target.c (new) +uint64_t common_semi_arg(CPUState *cs, int argno) +{ + CPUHexagonState *env = cpu_env(cs); -+ return arch_get_thread_reg(env, HEX_REG_R00 + argno); ++ return env->gpr[HEX_REG_R00 + argno]; +} + +void common_semi_set_ret(CPUState *cs, uint64_t ret) +{ + CPUHexagonState *env = cpu_env(cs); -+ arch_set_thread_reg(env, HEX_REG_R00, ret); ++ env->gpr[HEX_REG_R00] = ret; +} + +void common_semi_set_err(CPUState *cs, int err) +{ + CPUHexagonState *env = cpu_env(cs); -+ arch_set_thread_reg(env, HEX_REG_R01, err); ++ env->gpr[HEX_REG_R01] = err; +} + +bool common_semi_sys_exit_is_extended(CPUState *cs) @@ target/hexagon/common-semi-target.c (new) +uint64_t common_semi_stack_bottom(CPUState *cs) +{ + CPUHexagonState *env = cpu_env(cs); -+ return arch_get_thread_reg(env, HEX_REG_SP); ++ return env->gpr[HEX_REG_SP]; +} + +bool common_semi_has_synccache(CPUArchState *env) @@ target/hexagon/hexswi.c + g_assert(bql_locked()); + init_semihosting_guestfds(); + -+ what_swi = arch_get_thread_reg(env, HEX_REG_R00); -+ swi_info = arch_get_thread_reg(env, HEX_REG_R01); ++ what_swi = env->gpr[HEX_REG_R00]; ++ swi_info = env->gpr[HEX_REG_R01]; + + qemu_log_mask(CPU_LOG_INT, + "sim_handle_trap0: swi=0x%" PRIx32 + " info=0x%" PRIx32 " PC=0x%" PRIx32 + " thread=%" PRId32 "\n", + (uint32_t)what_swi, (uint32_t)swi_info, -+ (uint32_t)arch_get_thread_reg(env, HEX_REG_PC), ++ (uint32_t)env->gpr[HEX_REG_PC], + (uint32_t)env->threadId); + + if (!is_hexagon_specific_swi_flag(what_swi)) { @@ target/hexagon/hexswi.c + + case HEX_SYS_EXCEPTION: + { -+ uint32_t ret = arch_get_thread_reg(env, HEX_REG_R02); -+ arch_set_system_reg(env, HEX_SREG_MODECTL, 0); ++ uint32_t ret = env->gpr[HEX_REG_R02]; ++ env->gpr[HEX_SREG_MODECTL] = 0; + gdb_exit(ret); + exit(ret); + } @@ target/hexagon/hexswi.c + /* TODO: implement other hexagon-specific semihosting calls */ + + default: -+ qemu_log_mask(LOG_GUEST_ERROR, ++ qemu_log_mask(LOG_UNIMP, + "unknown swi request: 0x%" PRIx32 "\n", + (uint32_t)what_swi); + common_semi_cb(cs, -1, ENOSYS); @@ target/hexagon/hexswi.c: void hexagon_cpu_do_interrupt(CPUState *cs) ## target/hexagon/meson.build ## @@ target/hexagon/meson.build: hexagon_softmmu_ss.add(files( + 'hex_interrupts.c', + 'hexswi.c', 'machine.c', ++ 'common-semi-target.c', )) -+hexagon_softmmu_ss.add(when: 'CONFIG_ARM_COMPATIBLE_SEMIHOSTING', -+ if_true: files('common-semi-target.c')) -+ # - # Step 4.5 - # We use flex/bison based idef-parser to generate TCG code for a lot 8: 35d0c39f75 = 9: 2b36fa4993 semihosting: add ftruncate helper (to be used for hexagon) 9: 924d0069ad ! 10: dde7923648 target/hexagon: add main arch-specific semihosting operations @@ target/hexagon/hexswi.c: static void sim_handle_trap0(CPUHexagonState *env) + err = errno; + } + if (rc == 0) { -+ sys_stat.dev = st_buf.st_dev; -+ sys_stat.ino = st_buf.st_ino; -+ sys_stat.mode = st_buf.st_mode; -+ sys_stat.nlink = (uint32_t) st_buf.st_nlink; -+ sys_stat.rdev = st_buf.st_rdev; -+ sys_stat.size = (uint32_t) st_buf.st_size; -+#if defined(__linux__) -+ sys_stat.atime = (uint32_t) st_buf.st_atim.tv_sec; -+ sys_stat.mtime = (uint32_t) st_buf.st_mtim.tv_sec; -+ sys_stat.ctime = (uint32_t) st_buf.st_ctim.tv_sec; -+#elif defined(_WIN32) -+ sys_stat.atime = st_buf.st_atime; -+ sys_stat.mtime = st_buf.st_mtime; -+ sys_stat.ctime = st_buf.st_ctime; -+#endif ++ sys_stat.dev = cpu_to_le64(st_buf.st_dev); ++ sys_stat.ino = cpu_to_le64(st_buf.st_ino); ++ sys_stat.mode = cpu_to_le32(st_buf.st_mode); ++ sys_stat.nlink = cpu_to_le32((uint32_t) st_buf.st_nlink); ++ sys_stat.rdev = cpu_to_le64(st_buf.st_rdev); ++ sys_stat.size = cpu_to_le32((uint32_t) st_buf.st_size); ++ sys_stat.atime = cpu_to_le32(st_buf.st_atime); ++ sys_stat.mtime = cpu_to_le32(st_buf.st_mtime); ++ sys_stat.ctime = cpu_to_le32(st_buf.st_ctime); + } + hexagon_read_memory(env, swi_info + 4, 4, &statBufferAddr, retaddr); + @@ target/hexagon/hexswi.c: static void sim_handle_trap0(CPUHexagonState *env) + case HEX_SYS_READ_TCYCLES: + case HEX_SYS_READ_ICOUNT: + { -+ arch_set_thread_reg(env, HEX_REG_R00, 0); -+ arch_set_thread_reg(env, HEX_REG_R01, 0); ++ env->gpr[HEX_REG_R00] = 0; ++ env->gpr[HEX_REG_R01] = 0; + break; + } + + case HEX_SYS_READ_PCYCLES: + { -+ arch_set_thread_reg(env, HEX_REG_R00, -+ arch_get_system_reg(env, HEX_SREG_PCYCLELO)); -+ arch_set_thread_reg(env, HEX_REG_R01, -+ arch_get_system_reg(env, HEX_SREG_PCYCLEHI)); ++ env->gpr[HEX_REG_R00] = hexagon_get_sys_pcycle_count_low(env); ++ env->gpr[HEX_REG_R01] = hexagon_get_sys_pcycle_count_high(env); + break; + } + @@ target/hexagon/hexswi.c: static void sim_handle_trap0(CPUHexagonState *env) + break; default: - qemu_log_mask(LOG_GUEST_ERROR, + qemu_log_mask(LOG_UNIMP, 10: a81c46b955 ! 11: 0664a4a5a9 target/hexagon: add COREDUMP semihosting operation @@ target/hexagon/hexswi.c: static void common_semi_ftell_cb(CPUState *cs, uint64_t +static void coredump(CPUHexagonState *env) +{ -+ uint32_t ssr = arch_get_system_reg(env, HEX_SREG_SSR); ++ uint32_t ssr = env->t_sreg[HEX_SREG_SSR]; + FILE *f = qemu_log_trylock(); + + if (!f) { @@ target/hexagon/hexswi.c: static void common_semi_ftell_cb(CPUState *cs, uint64_t + break; + case HEX_CAUSE_MISALIGNED_LOAD: + fprintf(f, "0x%x, Misaligned Load @ 0x%" PRIx32, -+ HEX_CAUSE_MISALIGNED_LOAD, -+ arch_get_system_reg(env, HEX_SREG_BADVA)); ++ HEX_CAUSE_MISALIGNED_LOAD, env->t_sreg[HEX_SREG_BADVA]); + break; + case HEX_CAUSE_MISALIGNED_STORE: + fprintf(f, "0x%x, Misaligned Store @ 0x%" PRIx32, -+ HEX_CAUSE_MISALIGNED_STORE, -+ arch_get_system_reg(env, HEX_SREG_BADVA)); ++ HEX_CAUSE_MISALIGNED_STORE, env->t_sreg[HEX_SREG_BADVA]); + break; + case HEX_CAUSE_PRIV_NO_READ: + fprintf(f, "0x%x, Privilege violation: " + "user/guest read permission @ 0x%" PRIx32, -+ HEX_CAUSE_PRIV_NO_READ, -+ arch_get_system_reg(env, HEX_SREG_BADVA)); ++ HEX_CAUSE_PRIV_NO_READ, env->t_sreg[HEX_SREG_BADVA]); + break; + case HEX_CAUSE_PRIV_NO_WRITE: + fprintf(f, "0x%x, Privilege violation: " + "user/guest write permission @ 0x%" PRIx32, -+ HEX_CAUSE_PRIV_NO_WRITE, -+ arch_get_system_reg(env, HEX_SREG_BADVA)); ++ HEX_CAUSE_PRIV_NO_WRITE, env->t_sreg[HEX_SREG_BADVA]); + break; + case HEX_CAUSE_PRIV_NO_UREAD: + fprintf(f, "0x%x, Privilege violation:" + " user read permission @ 0x%" PRIx32, -+ HEX_CAUSE_PRIV_NO_UREAD, -+ arch_get_system_reg(env, HEX_SREG_BADVA)); ++ HEX_CAUSE_PRIV_NO_UREAD, env->t_sreg[HEX_SREG_BADVA]); + break; + case HEX_CAUSE_PRIV_NO_UWRITE: + fprintf(f, "0x%x, Privilege violation:" + " user write permission @ 0x%" PRIx32, -+ HEX_CAUSE_PRIV_NO_UWRITE, -+ arch_get_system_reg(env, HEX_SREG_BADVA)); ++ HEX_CAUSE_PRIV_NO_UWRITE, env->t_sreg[HEX_SREG_BADVA]); + break; + case HEX_CAUSE_COPROC_LDST: + fprintf(f, "0x%x, Coprocessor VMEM address error @ 0x%" PRIx32, -+ HEX_CAUSE_COPROC_LDST, -+ arch_get_system_reg(env, HEX_SREG_BADVA)); ++ HEX_CAUSE_COPROC_LDST, env->t_sreg[HEX_SREG_BADVA]); + break; + case HEX_CAUSE_STACK_LIMIT: + fprintf(f, "0x%x, Stack limit check error", 11: 289e5cb2d9 ! 12: 71b686df7f target/hexagon: Add an errno mapping @@ target/hexagon/hexswi.c: static void do_preload(CPUHexagonState *env, target_ulo } +/* Hexagon semihosting errno values */ -+#define HEX_EINVAL 22 -+#define HEX_ERRNOS \ -+ HEX_ERRNO(EPERM, 1) \ -+ HEX_ERRNO(ENOENT, 2) \ -+ HEX_ERRNO(EINTR, 4) \ -+ HEX_ERRNO(EIO, 5) \ -+ HEX_ERRNO(ENXIO, 6) \ -+ HEX_ERRNO(EBADF, 9) \ -+ HEX_ERRNO(EAGAIN, 11) \ -+ HEX_ERRNO(ENOMEM, 12) \ -+ HEX_ERRNO(EACCES, 13) \ -+ HEX_ERRNO(EFAULT, 14) \ -+ HEX_ERRNO(EBUSY, 16) \ -+ HEX_ERRNO(EEXIST, 17) \ -+ HEX_ERRNO(EXDEV, 18) \ -+ HEX_ERRNO(ENODEV, 19) \ -+ HEX_ERRNO(ENOTDIR, 20) \ -+ HEX_ERRNO(EISDIR, 21) \ -+ HEX_ERRNO(EINVAL, HEX_EINVAL) \ -+ HEX_ERRNO(ENFILE, 23) \ -+ HEX_ERRNO(EMFILE, 24) \ -+ HEX_ERRNO(ENOTTY, 25) \ -+ HEX_ERRNO(ETXTBSY, 26) \ -+ HEX_ERRNO(EFBIG, 27) \ -+ HEX_ERRNO(ENOSPC, 28) \ -+ HEX_ERRNO(ESPIPE, 29) \ -+ HEX_ERRNO(EROFS, 30) \ -+ HEX_ERRNO(EMLINK, 31) \ -+ HEX_ERRNO(EPIPE, 32) \ -+ HEX_ERRNO(ERANGE, 34) \ -+ HEX_ERRNO(ENAMETOOLONG, 36) \ -+ HEX_ERRNO(ENOSYS, 38) \ -+ HEX_ERRNO(ELOOP, 40) \ -+ HEX_ERRNO(EOVERFLOW, 75) ++enum { ++ TARGET_EPERM = 1, ++ TARGET_ENOENT = 2, ++ TARGET_EINTR = 4, ++ TARGET_EIO = 5, ++ TARGET_ENXIO = 6, ++ TARGET_EBADF = 9, ++ TARGET_EAGAIN = 11, ++ TARGET_ENOMEM = 12, ++ TARGET_EACCES = 13, ++ TARGET_EFAULT = 14, ++ TARGET_EBUSY = 16, ++ TARGET_EEXIST = 17, ++ TARGET_EXDEV = 18, ++ TARGET_ENODEV = 19, ++ TARGET_ENOTDIR = 20, ++ TARGET_EISDIR = 21, ++ TARGET_EINVAL = 22, ++ TARGET_ENFILE = 23, ++ TARGET_EMFILE = 24, ++ TARGET_ENOTTY = 25, ++ TARGET_ETXTBSY = 26, ++ TARGET_EFBIG = 27, ++ TARGET_ENOSPC = 28, ++ TARGET_ESPIPE = 29, ++ TARGET_EROFS = 30, ++ TARGET_EMLINK = 31, ++ TARGET_EPIPE = 32, ++ TARGET_ERANGE = 34, ++ TARGET_ENAMETOOLONG = 36, ++ TARGET_ENOSYS = 38, ++ TARGET_ELOOP = 40, ++ TARGET_EOVERFLOW = 75, ++}; + +/* Map host errno to hexagon semihosting errno */ ++static uint32_t errno_h2g(uint32_t err) { ++ switch (err) { ++ case 0: return 0; ++ case EPERM: return TARGET_EPERM; ++ case ENOENT: return TARGET_ENOENT; ++ case EINTR: return TARGET_EINTR; ++ case EIO: return TARGET_EIO; ++ case ENXIO: return TARGET_ENXIO; ++ case EBADF: return TARGET_EBADF; ++ case EAGAIN: return TARGET_EAGAIN; ++ case ENOMEM: return TARGET_ENOMEM; ++ case EACCES: return TARGET_EACCES; ++ case EFAULT: return TARGET_EFAULT; ++ case EBUSY: return TARGET_EBUSY; ++ case EEXIST: return TARGET_EEXIST; ++ case EXDEV: return TARGET_EXDEV; ++ case ENODEV: return TARGET_ENODEV; ++ case ENOTDIR: return TARGET_ENOTDIR; ++ case EISDIR: return TARGET_EISDIR; ++ case EINVAL: return TARGET_EINVAL; ++ case ENFILE: return TARGET_ENFILE; ++ case EMFILE: return TARGET_EMFILE; ++ case ENOTTY: return TARGET_ENOTTY; ++ case ETXTBSY: return TARGET_ETXTBSY; ++ case EFBIG: return TARGET_EFBIG; ++ case ENOSPC: return TARGET_ENOSPC; ++ case ESPIPE: return TARGET_ESPIPE; ++ case EROFS: return TARGET_EROFS; ++ case EMLINK: return TARGET_EMLINK; ++ case EPIPE: return TARGET_EPIPE; ++ case ERANGE: return TARGET_ERANGE; ++ case ENAMETOOLONG: return TARGET_ENAMETOOLONG; ++ case ENOSYS: return TARGET_ENOSYS; ++ case ELOOP: return TARGET_ELOOP; ++ case EOVERFLOW: return TARGET_EOVERFLOW; ++ } ++ return TARGET_EINVAL; ++} ++ +static void semi_cb(CPUState *cs, uint64_t ret, int err) +{ -+#define HEX_ERRNO(NAME, CODE) case NAME: err = CODE; break; -+ switch (err) { -+ case 0: -+ break; -+ HEX_ERRNOS -+ default: -+ err = HEX_EINVAL; -+ break; -+ } -+ common_semi_cb(cs, ret, err); ++ common_semi_cb(cs, ret, errno_h2g(err)); +} + static void common_semi_ftell_cb(CPUState *cs, uint64_t ret, int err) @@ target/hexagon/hexswi.c: static void sim_handle_trap0(CPUHexagonState *env) "SWI call %" PRIx32 " is unimplemented in QEMU\n", @@ target/hexagon/hexswi.c: static void sim_handle_trap0(CPUHexagonState *env) - qemu_log_mask(LOG_GUEST_ERROR, + qemu_log_mask(LOG_UNIMP, "unknown swi request: 0x%" PRIx32 "\n", (uint32_t)what_swi); - common_semi_cb(cs, -1, ENOSYS); 12: 61d0585371 = 13: abcd31dac2 python/machine: support routing semihosting output to the test console 13: 12b2448ce3 ! 14: 0aab35393d tests/functional: Add hexagon semihosting systests @@ tests/functional/hexagon/test_systests.py (new) + self.archive_extract(self.ASSET_TARBALL) + + def binary(self, name): -+ """Return the full path to binary *name* inside bin dir.""" + path = self.scratch_file(*_TARBALL_BIN_PATH, name) + self.assertTrue(os.path.exists(path)) + return path + + def run_exit_zero(self, binary_name, *extra_args, machine="V66G_1024"): -+ """Launch *binary_name* and assert it exits with code 0. -+ -+ :param binary_name: name of the binary inside bin dir. -+ :param extra_args: optional pairs of (flag, value) strings passed -+ to set_vm_arg(), e.g. ('-append', 'myarg'). -+ :param machine: QEMU machine type (default "V66G_1024"). -+ """ + self.set_machine(machine) + self.set_vm_arg("-display", "none") + self.set_vm_arg("-kernel", self.binary(binary_name)) @@ tests/functional/hexagon/test_systests.py (new) + + def run_console_pattern(self, binary_name, pattern, *extra_args, + machine="V66G_1024"): -+ """Launch *binary_name* and wait for *pattern* on the semihosting console. -+ -+ :param binary_name: name of the binary inside bin dir. -+ :param pattern: string pattern to wait for via wait_for_console_pattern. -+ :param extra_args: optional pairs of (flag, value) strings passed -+ to set_vm_arg(), e.g. ('-append', 'myarg'). -+ :param machine: QEMU machine type (default "V66G_1024"). -+ """ + self.set_machine(machine) + self.set_vm_arg("-display", "none") + self.set_vm_arg("-kernel", self.binary(binary_name)) -- 2.37.2
