Wire up ARM_COMPATIBLE_SEMIHOSTING for LoongArch. The semihosting ABI (i.e. "dbcl 0xab" for semihosting call and Arm compatible settings) is confirmed by LA132 (1C103)'s OpenOCD implementation.
Signed-off-by: Jiaxun Yang <jiaxun.y...@flygoat.com> --- configs/targets/loongarch64-linux-user.mak | 2 + linux-user/loongarch64/cpu_loop.c | 12 ++++++ linux-user/qemu.h | 5 ++- qemu-options.hx | 11 ++--- target/loongarch/Kconfig | 1 + target/loongarch/common-semi-target.h | 49 ++++++++++++++++++++++ target/loongarch/cpu.c | 6 +++ target/loongarch/cpu.h | 3 ++ .../tcg/insn_trans/trans_privileged.c.inc | 41 +++++++++--------- target/loongarch/tcg/translate.c | 1 + tests/tcg/loongarch64/semicall.h | 19 +++++++++ 11 files changed, 124 insertions(+), 26 deletions(-) diff --git a/configs/targets/loongarch64-linux-user.mak b/configs/targets/loongarch64-linux-user.mak index dfded79dfa8531dfd0cb8928e47922810d4b7f41..ad3754dfdd0c39ebfa8c308326f744888e34c10e 100644 --- a/configs/targets/loongarch64-linux-user.mak +++ b/configs/targets/loongarch64-linux-user.mak @@ -4,3 +4,5 @@ TARGET_BASE_ARCH=loongarch TARGET_XML_FILES=gdb-xml/loongarch-base64.xml gdb-xml/loongarch-fpu.xml gdb-xml/loongarch-lsx.xml gdb-xml/loongarch-lasx.xml TARGET_SYSTBL=syscall.tbl TARGET_SYSTBL_ABI=common,64 +CONFIG_SEMIHOSTING=y +CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y diff --git a/linux-user/loongarch64/cpu_loop.c b/linux-user/loongarch64/cpu_loop.c index 73d7b6796a4261a77e73d8504b4ba9a722ae822d..426a772e6929e8e3c4b6e6f387b9c0ecf102b8c6 100644 --- a/linux-user/loongarch64/cpu_loop.c +++ b/linux-user/loongarch64/cpu_loop.c @@ -10,6 +10,7 @@ #include "user-internals.h" #include "cpu_loop-common.h" #include "signal-common.h" +#include "semihosting/common-semi.h" void cpu_loop(CPULoongArchState *env) { @@ -84,6 +85,10 @@ void cpu_loop(CPULoongArchState *env) case EXCCODE_ASXD: env->CSR_EUEN |= R_CSR_EUEN_ASXE_MASK; break; + case EXCCODE_SEMIHOST: + do_common_semihosting(cs); + set_pc(env, env->pc + 4); + break; case EXCP_ATOMIC: cpu_exec_step_atomic(cs); @@ -99,6 +104,9 @@ void cpu_loop(CPULoongArchState *env) void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs) { + CPUState *cpu = env_cpu(env); + TaskState *ts = get_task_state(cpu); + struct image_info *info = ts->info; int i; for (i = 0; i < 32; i++) { @@ -106,4 +114,8 @@ void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs) } env->pc = regs->csr.era; + ts->stack_base = info->start_stack; + ts->heap_base = info->brk; + /* This will be filled in on the first SYS_HEAPINFO call. */ + ts->heap_limit = 0; } diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 67bc81b1499014739b002509a4e7a18afe977433..8ddbfa886881e5d7d02f45f8657d985efd863d96 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -103,7 +103,7 @@ struct TaskState { FPA11 fpa; # endif #endif -#if defined(TARGET_ARM) || defined(TARGET_RISCV) +#if defined(TARGET_ARM) || defined(TARGET_LOONGARCH) || defined(TARGET_RISCV) int swi_errno; #endif #if defined(TARGET_I386) && !defined(TARGET_X86_64) @@ -121,7 +121,8 @@ struct TaskState { #ifdef TARGET_M68K abi_ulong tp_value; #endif -#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_RISCV) +#if defined(TARGET_ARM) || defined(TARGET_LOONGARCH) || \ + defined(TARGET_M68K) || defined(TARGET_RISCV) /* Extra fields for semihosted binaries. */ abi_ulong heap_base; abi_ulong heap_limit; diff --git a/qemu-options.hx b/qemu-options.hx index cc694d3b890c8ad9c5fad0a1f689781191d8e97a..0c4d599ab9e4e0e443aedc1b1c8733be1ab524ed 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -5011,10 +5011,11 @@ 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_LOONGARCH) SRST ``-semihosting`` - Enable :ref:`Semihosting` mode (ARM, M68K, Xtensa, MIPS, RISC-V only). + Enable :ref:`Semihosting` mode (ARM, M68K, Xtensa, MIPS, RISC-V, + LoongArch only). .. warning:: Note that this allows guest direct access to the host filesystem, so @@ -5027,11 +5028,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_LOONGARCH) 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, + LoongArch only). .. warning:: Note that this allows guest direct access to the host filesystem, so diff --git a/target/loongarch/Kconfig b/target/loongarch/Kconfig index 46b26b1a85715e779672bea93152a3c62c170fe2..ba8918d7045e9056107415612a7c756701923231 100644 --- a/target/loongarch/Kconfig +++ b/target/loongarch/Kconfig @@ -1,2 +1,3 @@ config LOONGARCH64 bool + select ARM_COMPATIBLE_SEMIHOSTING if TCG diff --git a/target/loongarch/common-semi-target.h b/target/loongarch/common-semi-target.h new file mode 100644 index 0000000000000000000000000000000000000000..066d2ea1af35861521beabfc4f31c496c9bc3e03 --- /dev/null +++ b/target/loongarch/common-semi-target.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Target-specific parts of semihosting/arm-compat-semi.c. + * + * Copyright (c) 2005, 2007 CodeSourcery. + * Copyright (c) 2019, 2022 Linaro + * Copyright (c) 2024 Jiaxun Yang <jiaxun.y...@flygoat.com> + */ + +#ifndef TARGET_LOONGARCH_COMMON_SEMI_TARGET_H +#define TARGET_LOONGARCH_COMMON_SEMI_TARGET_H + +static inline target_ulong common_semi_arg(CPUState *cs, int argno) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + return env->gpr[4 + argno]; +} + +static inline void common_semi_set_ret(CPUState *cs, target_ulong ret) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + env->gpr[4] = ret; +} + +static inline bool common_semi_sys_exit_extended(CPUState *cs, int nr) +{ + return (nr == TARGET_SYS_EXIT_EXTENDED || sizeof(target_ulong) == 8); +} + +static inline bool is_64bit_semihosting(CPUArchState *env) +{ + return !is_va32(env); +} + +static inline target_ulong common_semi_stack_bottom(CPUState *cs) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + return env->gpr[3]; +} + +static inline bool common_semi_has_synccache(CPUArchState *env) +{ + return true; +} + +#endif diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index 57cc4f314bf707bea7f2c0eca5590841e68a2a97..9591f091f35eb001f255dc00b8a26276c9624a96 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -21,6 +21,7 @@ #include "cpu-csr.h" #ifndef CONFIG_USER_ONLY #include "sysemu/reset.h" +#include "semihosting/common-semi.h" #endif #include "vec.h" #ifdef CONFIG_KVM @@ -71,6 +72,7 @@ static const struct TypeExcp excp_names[] = { {EXCCODE_BCE, "Bound Check Exception"}, {EXCCODE_SXD, "128 bit vector instructions Disable exception"}, {EXCCODE_ASXD, "256 bit vector instructions Disable exception"}, + {EXCCODE_SEMIHOST, "Semihosting"}, {EXCP_HLT, "EXCP_HLT"}, }; @@ -179,6 +181,10 @@ static void loongarch_cpu_do_interrupt(CPUState *cs) } switch (cs->exception_index) { + case EXCCODE_SEMIHOST: + do_common_semihosting(cs); + set_pc(env, env->pc + 4); + return; case EXCCODE_DBP: env->CSR_DBG = FIELD_DP64(env->CSR_DBG, CSR_DBG, DCL, 1); env->CSR_DBG = FIELD_DP64(env->CSR_DBG, CSR_DBG, ECODE, 0xC); diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h index 86c86c6c958db1a215a3e76a27f379bd4a095fb6..2b466a046d552a8c62cb0c4f57c3ac50c64f21a7 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -115,6 +115,9 @@ FIELD(FCSR0, CAUSE, 24, 5) #define EXCCODE_BTE EXCODE(21, 0) #define EXCCODE_DBP EXCODE(26, 0) /* Reserved subcode used for debug */ +/* QEMU Internal Exceptions */ +#define EXCCODE_SEMIHOST EXCODE(63, 0) + /* cpucfg[0] bits */ FIELD(CPUCFG0, PRID, 0, 32) diff --git a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc index 7e4ec93edb3c415268489014def22e85a0de6fb4..c9776081b8026b7aaafd49a0c55aab1779bc206b 100644 --- a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc +++ b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc @@ -7,6 +7,28 @@ #include "cpu-csr.h" +static bool check_plv(DisasContext *ctx) +{ + if (ctx->plv == MMU_PLV_USER) { + generate_exception(ctx, EXCCODE_IPE); + return true; + } + return false; +} + +static bool trans_dbcl(DisasContext *ctx, arg_dbcl *a) +{ + if (semihosting_enabled(ctx->plv == MMU_PLV_USER) && a->imm == 0xab) { + generate_exception(ctx, EXCCODE_SEMIHOST); + return true; + } + if (check_plv(ctx)) { + return false; + } + generate_exception(ctx, EXCCODE_DBP); + return true; +} + #ifdef CONFIG_USER_ONLY #define GEN_FALSE_TRANS(name) \ @@ -37,7 +59,6 @@ GEN_FALSE_TRANS(cacop) GEN_FALSE_TRANS(ldpte) GEN_FALSE_TRANS(lddir) GEN_FALSE_TRANS(ertn) -GEN_FALSE_TRANS(dbcl) GEN_FALSE_TRANS(idle) #else @@ -151,15 +172,6 @@ static const CSRInfo csr_info[] = { CSR_OFF(DSAVE), }; -static bool check_plv(DisasContext *ctx) -{ - if (ctx->plv == MMU_PLV_USER) { - generate_exception(ctx, EXCCODE_IPE); - return true; - } - return false; -} - static const CSRInfo *get_csr(unsigned csr_num) { const CSRInfo *csr; @@ -475,15 +487,6 @@ static bool trans_ertn(DisasContext *ctx, arg_ertn *a) return true; } -static bool trans_dbcl(DisasContext *ctx, arg_dbcl *a) -{ - if (check_plv(ctx)) { - return false; - } - generate_exception(ctx, EXCCODE_DBP); - return true; -} - static bool trans_idle(DisasContext *ctx, arg_idle *a) { if (check_plv(ctx)) { diff --git a/target/loongarch/tcg/translate.c b/target/loongarch/tcg/translate.c index 1fca4afc731c048816618d87610a0cc0fe7579b1..9eaac98034fe7f3481007c3d69794a973d326f00 100644 --- a/target/loongarch/tcg/translate.c +++ b/target/loongarch/tcg/translate.c @@ -16,6 +16,7 @@ #include "exec/log.h" #include "qemu/qemu-print.h" #include "fpu/softfloat.h" +#include "semihosting/semihost.h" #include "translate.h" #include "internals.h" #include "vec.h" diff --git a/tests/tcg/loongarch64/semicall.h b/tests/tcg/loongarch64/semicall.h new file mode 100644 index 0000000000000000000000000000000000000000..0f29f7a52cee9b3273aba1c773e8f9d91fde7011 --- /dev/null +++ b/tests/tcg/loongarch64/semicall.h @@ -0,0 +1,19 @@ +/* + * Semihosting Tests - LoongArch Helper + * + * Copyright (c) 2024 Jiaxun Yang <jiaxun.y...@flygoat.com> + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +uintptr_t __semi_call(uintptr_t type, uintptr_t arg0) +{ + register uintptr_t t asm("a0") = type; + register uintptr_t a0 asm("a1") = arg0; + + asm("dbcl 0xab\n\t" + : "=r" (t) + : "r" (t), "r" (a0)); + + return t; +} --- base-commit: 8529d6fb65882418a924b4c4817e15ffda2a6839 change-id: 20241221-semihosting-cf18f73325f9 prerequisite-change-id: 20241219-la-booting-d6d8427a7790:v2 prerequisite-patch-id: d034c987c8746e03b7d0c2556e98fda93e32a84c prerequisite-patch-id: 3f9c8f90f5466f56ba3dd3569be8ed4f1b0452e2 Best regards, -- Jiaxun Yang <jiaxun.y...@flygoat.com>