Signed-off-by: Bastian Koppelmann <kbast...@mail.uni-paderborn.de> --- target/tricore/helper.h | 1 + target/tricore/meson.build | 1 + target/tricore/tricore-semi.c | 197 ++++++++++++++++++++++++++++++++++ 3 files changed, 199 insertions(+) create mode 100644 target/tricore/tricore-semi.c
diff --git a/target/tricore/helper.h b/target/tricore/helper.h index 1d97d078b0..587de1e06f 100644 --- a/target/tricore/helper.h +++ b/target/tricore/helper.h @@ -160,3 +160,4 @@ DEF_HELPER_2(psw_write, void, env, i32) DEF_HELPER_1(psw_read, i32, env) /* Exceptions */ DEF_HELPER_3(raise_exception_sync, noreturn, env, i32, i32) +DEF_HELPER_2(tricore_semihost, void, env, i32) diff --git a/target/tricore/meson.build b/target/tricore/meson.build index 45f49f0128..6cfc9355b7 100644 --- a/target/tricore/meson.build +++ b/target/tricore/meson.build @@ -6,6 +6,7 @@ tricore_ss.add(files( 'op_helper.c', 'translate.c', 'gdbstub.c', + 'tricore-semi.c', )) tricore_ss.add(zlib) diff --git a/target/tricore/tricore-semi.c b/target/tricore/tricore-semi.c new file mode 100644 index 0000000000..27e1bdc59d --- /dev/null +++ b/target/tricore/tricore-semi.c @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2023 Bastian Koppelmann + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/cpu_ldst.h" +#include "exec/helper-proto.h" +#include "exec/helper-gen.h" +#include "qemu/log.h" + +enum { + SYS__OPEN = 0x01, + SYS__CLOSE = 0x02, + SYS__LSEEK = 0x03, + SYS__READ = 0x04, + SYS__WRITE = 0x05, + SYS__CREAT = 0x06, + SYS__UNLINK = 0x07, + SYS__STAT = 0x08, + SYS__FSTAT = 0x09, + SYS__GETTIME = 0x0a, +}; + +enum { + TARGET_EPERM = 1, + TARGET_ENOENT = 2, + TARGET_ESRCH = 3, + TARGET_EINTR = 4, + TARGET_EIO = 5, + TARGET_ENXIO = 6, + TARGET_E2BIG = 7, + TARGET_ENOEXEC = 8, + TARGET_EBADF = 9, + TARGET_ECHILD = 10, + TARGET_EAGAIN = 11, + TARGET_ENOMEM = 12, + TARGET_EACCES = 13, + TARGET_EFAULT = 14, + TARGET_ENOTBLK = 15, + 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_ENOSYS = 88, + TARGET_ENOTEMPTY = 90, + TARGET_ENAMETOOLONG = 9 +}; + +static int +tricore_vio_errno_h2g(int host_errno) +{ + switch (host_errno) { + case EPERM: + return TARGET_EPERM; + case ENOENT: + return TARGET_ENOENT; + case ESRCH: + return TARGET_ESRCH; + case EINTR: + return TARGET_EINTR; + case EIO: + return TARGET_EIO; + case ENXIO: + return TARGET_ENXIO; + case E2BIG: + return TARGET_E2BIG; + case ENOEXEC: + return TARGET_ENOEXEC; + case EBADF: + return TARGET_EBADF; + case ECHILD: + return TARGET_ECHILD; + case EAGAIN: + return TARGET_EAGAIN; + case ENOMEM: + return TARGET_ENOMEM; + case EACCES: + return TARGET_EACCES; + case EFAULT: + return TARGET_EFAULT; + case ENOTBLK: + return TARGET_ENOTBLK; + 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 ENOSYS: + return TARGET_ENOSYS; + case ENOTEMPTY: + return TARGET_ENOTEMPTY; + case ENAMETOOLONG: + return TARGET_ENAMETOOLONG; + default: + return host_errno; + } +} + +/* + * Set return and errno values; the ___virtio function takes care + * that the target's errno variable gets updated from %d12, and + * eventually moves %d11 to the return register (%d2). + */ +static void tricore_vio_set_result(CPUTriCoreState *env, int retval, + int host_errno) +{ + env->gpr_d[11] = retval; + env->gpr_d[12] = tricore_vio_errno_h2g(host_errno); +} + + +#define TRICORE_VIO_MARKER 0x6f69765f /* "_vio" */ +#define TRICORE_VIO_EXIT_MARKER 0xE60 +#define TRICORE_VIO_SIMTEST_SUCC 0x900d +void helper_tricore_semihost(CPUTriCoreState *env, uint32_t pc) +{ + int syscall; + uint32_t marker = cpu_ldl_code(env, pc - 4); + + /* check for exit marker */ + if (extract32(marker, 0, 12) == TRICORE_VIO_EXIT_MARKER) { + if (env->gpr_a[14] == TRICORE_VIO_SIMTEST_SUCC) { + exit(0); + } else { + exit(env->gpr_a[14]); + } + } + + if (marker != TRICORE_VIO_MARKER) { + return; + } + + syscall = (int)env->gpr_d[12]; + switch (syscall) { + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s(%d): not implemented\n", __func__, + syscall); + tricore_vio_set_result(env, -1, ENOSYS); + break; + } +} -- 2.42.0