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(-)
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.yang@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.yang@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.yang@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.yang@flygoat.com>
© 2016 - 2024 Red Hat, Inc.