Message ID | 20220106094200.1801206-23-gaosong@loongson.cn |
---|---|
State | New |
Headers | show |
Series | Add LoongArch linux-user emulation support | expand |
On 1/6/22 17:41, Song Gao wrote: > Signed-off-by: Song Gao<gaosong@loongson.cn> > Signed-off-by: Xiaojuan Yang<yangxiaojuan@loongson.cn> > Reviewed-by: Richard Henderson<richard.henderson@linaro.org> > --- > configure | 3 + > linux-user/loongarch64/cpu_loop.c | 94 +++++++++++++++++++++++++++++ > linux-user/loongarch64/target_cpu.h | 34 +++++++++++ > 3 files changed, 131 insertions(+) > create mode 100644 linux-user/loongarch64/cpu_loop.c > create mode 100644 linux-user/loongarch64/target_cpu.h > > diff --git a/configure b/configure > index 030728d11e..93c4e5bd92 100755 > --- a/configure > +++ b/configure > @@ -659,6 +659,9 @@ case "$cpu" in > mips*) > cpu="mips" ;; > > + loongarch) > + cpu="loongarch64" ;; > + Do you really need this? Looking at the part above setting initial value for $cpu, you can only get here if $cpu is given on command-line, or returned by uname on a presumably LoongArch system not defining __loongarch64. Either would be unlikely though, and we really don't want to turn on 64-bit code for 32-bit hosts (that don't exist at the moment), so this case seems useless. > ppc) > CPU_CFLAGS="-m32" ;; > ppc64) > diff --git a/linux-user/loongarch64/cpu_loop.c b/linux-user/loongarch64/cpu_loop.c > new file mode 100644 > index 0000000000..6628d215ca > --- /dev/null > +++ b/linux-user/loongarch64/cpu_loop.c > @@ -0,0 +1,94 @@ > +/* SPDX-License-Identifier: GPL-2.0-or-later */ > +/* > + * QEMU LoongArch user cpu_loop. > + * > + * Copyright (c) 2021 Loongson Technology Corporation Limited > + */ > + > +#include "qemu/osdep.h" > +#include "qemu.h" > +#include "qemu-common.h" > +#include "user-internals.h" > +#include "cpu_loop-common.h" > +#include "signal-common.h" > + > +void cpu_loop(CPULoongArchState *env) > +{ > + CPUState *cs = env_cpu(env); > + int trapnr, si_code; > + abi_long ret; > + > + for (;;) { > + cpu_exec_start(cs); > + trapnr = cpu_exec(cs); > + cpu_exec_end(cs); > + process_queued_cpu_work(cs); > + > + switch (trapnr) { > + case EXCP_INTERRUPT: > + /* just indicate that signals should be handled asap */ > + break; > + case EXCP_SYSCALL: > + env->pc += 4; > + ret = do_syscall(env, env->gpr[11], > + env->gpr[4], env->gpr[5], > + env->gpr[6], env->gpr[7], > + env->gpr[8], env->gpr[9], > + -1, -1); > + if (ret == -QEMU_ERESTARTSYS) { > + env->pc -= 4; > + break; > + } > + if (ret == -QEMU_ESIGRETURN) { > + /* > + * Returning from a successful sigreturn syscall. > + * Avoid clobbering register state. > + */ > + break; > + } > + env->gpr[4] = ret; > + break; > + case EXCP_INE: > + force_sig_fault(TARGET_SIGILL, 0, env->pc); > + break; > + case EXCP_FPE: > + si_code = TARGET_FPE_FLTUNK; > + if (GET_FP_CAUSE(env->fcsr0) & FP_INVALID) { > + si_code = TARGET_FPE_FLTINV; > + } else if (GET_FP_CAUSE(env->fcsr0) & FP_DIV0) { > + si_code = TARGET_FPE_FLTDIV; > + } else if (GET_FP_CAUSE(env->fcsr0) & FP_OVERFLOW) { > + si_code = TARGET_FPE_FLTOVF; > + } else if (GET_FP_CAUSE(env->fcsr0) & FP_UNDERFLOW) { > + si_code = TARGET_FPE_FLTUND; > + } else if (GET_FP_CAUSE(env->fcsr0) & FP_INEXACT) { > + si_code = TARGET_FPE_FLTRES; > + } > + force_sig_fault(TARGET_SIGFPE, si_code, env->pc); > + break; > + case EXCP_DEBUG: > + case EXCP_BREAK: > + force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc); > + break; > + case EXCP_ATOMIC: > + cpu_exec_step_atomic(cs); > + break; > + default: > + EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", > + trapnr); > + exit(EXIT_FAILURE); > + } > + process_pending_signals(env); > + } > +} > + > +void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs) > +{ > + int i; > + > + for (i = 0; i < 32; i++) { > + env->gpr[i] = regs->regs[i]; > + } > + env->pc = regs->csr.era; > + > +} > diff --git a/linux-user/loongarch64/target_cpu.h b/linux-user/loongarch64/target_cpu.h > new file mode 100644 > index 0000000000..a29af66156 > --- /dev/null > +++ b/linux-user/loongarch64/target_cpu.h > @@ -0,0 +1,34 @@ > +/* SPDX-License-Identifier: GPL-2.0-or-later */ > +/* > + * LoongArch specific CPU ABI and functions for linux-user > + * > + * Copyright (c) 2021 Loongson Technology Corporation Limited > + */ > + > +#ifndef LOONGARCH_TARGET_CPU_H > +#define LOONGARCH_TARGET_CPU_H > + > +static inline void cpu_clone_regs_child(CPULoongArchState *env, > + target_ulong newsp, unsigned flags) > +{ > + if (newsp) { > + env->gpr[3] = newsp; > + } > + env->gpr[4] = 0; > +} > + > +static inline void cpu_clone_regs_parent(CPULoongArchState *env, > + unsigned flags) > +{ > +} > + > +static inline void cpu_set_tls(CPULoongArchState *env, target_ulong newtls) > +{ > + env->gpr[2] = newtls; > +} > + > +static inline abi_ulong get_sp_from_cpustate(CPULoongArchState *state) > +{ > + return state->gpr[3]; > +} > +#endif
diff --git a/configure b/configure index 030728d11e..93c4e5bd92 100755 --- a/configure +++ b/configure @@ -659,6 +659,9 @@ case "$cpu" in mips*) cpu="mips" ;; + loongarch) + cpu="loongarch64" ;; + ppc) CPU_CFLAGS="-m32" ;; ppc64) diff --git a/linux-user/loongarch64/cpu_loop.c b/linux-user/loongarch64/cpu_loop.c new file mode 100644 index 0000000000..6628d215ca --- /dev/null +++ b/linux-user/loongarch64/cpu_loop.c @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QEMU LoongArch user cpu_loop. + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "qemu.h" +#include "qemu-common.h" +#include "user-internals.h" +#include "cpu_loop-common.h" +#include "signal-common.h" + +void cpu_loop(CPULoongArchState *env) +{ + CPUState *cs = env_cpu(env); + int trapnr, si_code; + abi_long ret; + + for (;;) { + cpu_exec_start(cs); + trapnr = cpu_exec(cs); + cpu_exec_end(cs); + process_queued_cpu_work(cs); + + switch (trapnr) { + case EXCP_INTERRUPT: + /* just indicate that signals should be handled asap */ + break; + case EXCP_SYSCALL: + env->pc += 4; + ret = do_syscall(env, env->gpr[11], + env->gpr[4], env->gpr[5], + env->gpr[6], env->gpr[7], + env->gpr[8], env->gpr[9], + -1, -1); + if (ret == -QEMU_ERESTARTSYS) { + env->pc -= 4; + break; + } + if (ret == -QEMU_ESIGRETURN) { + /* + * Returning from a successful sigreturn syscall. + * Avoid clobbering register state. + */ + break; + } + env->gpr[4] = ret; + break; + case EXCP_INE: + force_sig_fault(TARGET_SIGILL, 0, env->pc); + break; + case EXCP_FPE: + si_code = TARGET_FPE_FLTUNK; + if (GET_FP_CAUSE(env->fcsr0) & FP_INVALID) { + si_code = TARGET_FPE_FLTINV; + } else if (GET_FP_CAUSE(env->fcsr0) & FP_DIV0) { + si_code = TARGET_FPE_FLTDIV; + } else if (GET_FP_CAUSE(env->fcsr0) & FP_OVERFLOW) { + si_code = TARGET_FPE_FLTOVF; + } else if (GET_FP_CAUSE(env->fcsr0) & FP_UNDERFLOW) { + si_code = TARGET_FPE_FLTUND; + } else if (GET_FP_CAUSE(env->fcsr0) & FP_INEXACT) { + si_code = TARGET_FPE_FLTRES; + } + force_sig_fault(TARGET_SIGFPE, si_code, env->pc); + break; + case EXCP_DEBUG: + case EXCP_BREAK: + force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc); + break; + case EXCP_ATOMIC: + cpu_exec_step_atomic(cs); + break; + default: + EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", + trapnr); + exit(EXIT_FAILURE); + } + process_pending_signals(env); + } +} + +void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs) +{ + int i; + + for (i = 0; i < 32; i++) { + env->gpr[i] = regs->regs[i]; + } + env->pc = regs->csr.era; + +} diff --git a/linux-user/loongarch64/target_cpu.h b/linux-user/loongarch64/target_cpu.h new file mode 100644 index 0000000000..a29af66156 --- /dev/null +++ b/linux-user/loongarch64/target_cpu.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * LoongArch specific CPU ABI and functions for linux-user + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +#ifndef LOONGARCH_TARGET_CPU_H +#define LOONGARCH_TARGET_CPU_H + +static inline void cpu_clone_regs_child(CPULoongArchState *env, + target_ulong newsp, unsigned flags) +{ + if (newsp) { + env->gpr[3] = newsp; + } + env->gpr[4] = 0; +} + +static inline void cpu_clone_regs_parent(CPULoongArchState *env, + unsigned flags) +{ +} + +static inline void cpu_set_tls(CPULoongArchState *env, target_ulong newtls) +{ + env->gpr[2] = newtls; +} + +static inline abi_ulong get_sp_from_cpustate(CPULoongArchState *state) +{ + return state->gpr[3]; +} +#endif