From: Stacey Son <sson@FreeBSD.org>
Added function to initialize ARM CPU and check if it supports 64-bit mode.
Implemented CPU loop function to handle exceptions and emulate execution of instructions.
Added function to clone CPU state to create a new thread.
Included AArch64 specific CPU functions for bsd-user to set and receive thread-local-storage
value from the tpidr_el0 register.
Introduced structure for storing CPU register states for BSD-USER.
Signed-off-by: Stacey Son <sson@FreeBSD.org>
Signed-off-by: Ajeet Singh <itachis@FreeBSD.org>
Co-authored-by: Kyle Evans <kevans@freebsd.org>
Co-authored-by: Sean Bruno <sbruno@freebsd.org>
Co-authored-by: Jessica Clarke <jrtc27@jrtc27.com>
Reviewed-by: Warner Losh <imp@bsdimp.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
---
bsd-user/aarch64/target_arch_cpu.c | 31 +++++
bsd-user/aarch64/target_arch_cpu.h | 191 +++++++++++++++++++++++++++++
bsd-user/aarch64/target_syscall.h | 51 ++++++++
3 files changed, 273 insertions(+)
create mode 100644 bsd-user/aarch64/target_arch_cpu.c
create mode 100644 bsd-user/aarch64/target_arch_cpu.h
create mode 100644 bsd-user/aarch64/target_syscall.h
diff --git a/bsd-user/aarch64/target_arch_cpu.c b/bsd-user/aarch64/target_arch_cpu.c
new file mode 100644
index 0000000000..b2fa59efaf
--- /dev/null
+++ b/bsd-user/aarch64/target_arch_cpu.c
@@ -0,0 +1,31 @@
+/*
+ * ARM AArch64 specific CPU for bsd-user
+ *
+ * Copyright (c) 2015 Stacey Son
+ *
+ * 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 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 "target_arch.h"
+
+/* See cpu_set_user_tls() in arm64/arm64/vm_machdep.c */
+void target_cpu_set_tls(CPUARMState *env, target_ulong newtls)
+{
+ env->cp15.tpidr_el[0] = newtls;
+}
+
+target_ulong target_cpu_get_tls(CPUARMState *env)
+{
+ return env->cp15.tpidr_el[0];
+}
diff --git a/bsd-user/aarch64/target_arch_cpu.h b/bsd-user/aarch64/target_arch_cpu.h
new file mode 100644
index 0000000000..4e950305d3
--- /dev/null
+++ b/bsd-user/aarch64/target_arch_cpu.h
@@ -0,0 +1,191 @@
+/*
+ * ARM AArch64 cpu init and loop
+ *
+ * Copyright (c) 2015 Stacey Son
+ *
+ * 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 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/>.
+ */
+
+#ifndef TARGET_ARCH_CPU_H
+#define TARGET_ARCH_CPU_H
+
+#include "target_arch.h"
+#include "target/arm/syndrome.h"
+
+#define TARGET_DEFAULT_CPU_MODEL "any"
+
+static inline void target_cpu_init(CPUARMState *env,
+ struct target_pt_regs *regs)
+{
+ int i;
+
+ if (!(arm_feature(env, ARM_FEATURE_AARCH64))) {
+ fprintf(stderr, "The selected ARM CPU does not support 64 bit mode\n");
+ exit(1);
+ }
+ for (i = 0; i < 31; i++) {
+ env->xregs[i] = regs->regs[i];
+ }
+ env->pc = regs->pc;
+ env->xregs[31] = regs->sp;
+}
+
+
+static inline void target_cpu_loop(CPUARMState *env)
+{
+ CPUState *cs = env_cpu(env);
+ int trapnr, ec, fsc, si_code, si_signo;
+ uint64_t code, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
+ uint32_t pstate;
+ 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_SWI:
+ /* See arm64/arm64/trap.c cpu_fetch_syscall_args() */
+ code = env->xregs[8];
+ if (code == TARGET_FREEBSD_NR_syscall ||
+ code == TARGET_FREEBSD_NR___syscall) {
+ code = env->xregs[0];
+ arg1 = env->xregs[1];
+ arg2 = env->xregs[2];
+ arg3 = env->xregs[3];
+ arg4 = env->xregs[4];
+ arg5 = env->xregs[5];
+ arg6 = env->xregs[6];
+ arg7 = env->xregs[7];
+ arg8 = 0;
+ } else {
+ arg1 = env->xregs[0];
+ arg2 = env->xregs[1];
+ arg3 = env->xregs[2];
+ arg4 = env->xregs[3];
+ arg5 = env->xregs[4];
+ arg6 = env->xregs[5];
+ arg7 = env->xregs[6];
+ arg8 = env->xregs[7];
+ }
+ ret = do_freebsd_syscall(env, code, arg1, arg2, arg3,
+ arg4, arg5, arg6, arg7, arg8);
+ /*
+ * The carry bit is cleared for no error; set for error.
+ * See arm64/arm64/vm_machdep.c cpu_set_syscall_retval()
+ */
+ pstate = pstate_read(env);
+ if (ret >= 0) {
+ pstate &= ~PSTATE_C;
+ env->xregs[0] = ret;
+ } else if (ret == -TARGET_ERESTART) {
+ env->pc -= 4;
+ break;
+ } else if (ret != -TARGET_EJUSTRETURN) {
+ pstate |= PSTATE_C;
+ env->xregs[0] = -ret;
+ }
+ pstate_write(env, pstate);
+ break;
+
+ case EXCP_INTERRUPT:
+ /* Just indicate that signals should be handle ASAP. */
+ break;
+
+ case EXCP_UDEF:
+ force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPN, env->pc);
+ break;
+
+
+ case EXCP_PREFETCH_ABORT:
+ case EXCP_DATA_ABORT:
+ /* We should only arrive here with EC in {DATAABORT, INSNABORT}. */
+ ec = syn_get_ec(env->exception.syndrome);
+ assert(ec == EC_DATAABORT || ec == EC_INSNABORT);
+
+ /* Both EC have the same format for FSC, or close enough. */
+ fsc = extract32(env->exception.syndrome, 0, 6);
+ switch (fsc) {
+ case 0x04 ... 0x07: /* Translation fault, level {0-3} */
+ si_signo = TARGET_SIGSEGV;
+ si_code = TARGET_SEGV_MAPERR;
+ break;
+ case 0x09 ... 0x0b: /* Access flag fault, level {1-3} */
+ case 0x0d ... 0x0f: /* Permission fault, level {1-3} */
+ si_signo = TARGET_SIGSEGV;
+ si_code = TARGET_SEGV_ACCERR;
+ break;
+ case 0x11: /* Synchronous Tag Check Fault */
+ si_signo = TARGET_SIGSEGV;
+ si_code = /* TARGET_SEGV_MTESERR; */ TARGET_SEGV_ACCERR;
+ break;
+ case 0x21: /* Alignment fault */
+ si_signo = TARGET_SIGBUS;
+ si_code = TARGET_BUS_ADRALN;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ force_sig_fault(si_signo, si_code, env->exception.vaddress);
+ break;
+
+ case EXCP_DEBUG:
+ case EXCP_BKPT:
+ force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
+ break;
+
+ case EXCP_ATOMIC:
+ cpu_exec_step_atomic(cs);
+ break;
+
+ case EXCP_YIELD:
+ /* nothing to do here for user-mode, just resume guest code */
+ break;
+ default:
+ fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
+ trapnr);
+ cpu_dump_state(cs, stderr, 0);
+ abort();
+ } /* switch() */
+ process_pending_signals(env);
+ /*
+ * Exception return on AArch64 always clears the exclusive
+ * monitor, so any return to running guest code implies this.
+ * A strex (successful or otherwise) also clears the monitor, so
+ * we don't need to specialcase EXCP_STREX.
+ */
+ env->exclusive_addr = -1;
+ } /* for (;;) */
+}
+
+
+/* See arm64/arm64/vm_machdep.c cpu_fork() */
+static inline void target_cpu_clone_regs(CPUARMState *env, target_ulong newsp)
+{
+ if (newsp) {
+ env->xregs[31] = newsp;
+ }
+ env->regs[0] = 0;
+ env->regs[1] = 0;
+ pstate_write(env, 0);
+}
+
+static inline void target_cpu_reset(CPUArchState *env)
+{
+}
+
+
+#endif /* TARGET_ARCH_CPU_H */
diff --git a/bsd-user/aarch64/target_syscall.h b/bsd-user/aarch64/target_syscall.h
new file mode 100644
index 0000000000..08ae913c42
--- /dev/null
+++ b/bsd-user/aarch64/target_syscall.h
@@ -0,0 +1,51 @@
+/*
+ * ARM AArch64 specific CPU for bsd-user
+ *
+ * Copyright (c) 2015 Stacey D. Son <sson at Freebsd>
+ *
+ * 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 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/>.
+ */
+
+#ifndef BSD_USER_AARCH64_TARGET_SYSCALL_H
+#define BSD_USER_AARCH64_TARGET_SYSCALL_H
+
+/*
+ * The aarch64 registers are named:
+ *
+ * x0 through x30 - for 64-bit-wide access (same registers)
+ * Register '31' is one of two registers depending on the instruction context:
+ * For instructions dealing with the stack, it is the stack pointer, named rsp
+ * For all other instructions, it is a "zero" register, which returns 0 when
+ * read and discards data when written - named rzr (xzr, wzr)
+ *
+ * Usage during syscall/function call:
+ * r0-r7 are used for arguments and return values
+ * For syscalls, the syscall number is in r8
+ * r9-r15 are for temporary values (may get trampled)
+ * r16-r18 are used for intra-procedure-call and platform values (avoid)
+ * The called routine is expected to preserve r19-r28
+ * r29 and r30 are used as the frame register and link register (avoid)
+ * See the ARM Procedure Call Reference for details.
+ */
+struct target_pt_regs {
+ uint64_t regs[31];
+ uint64_t sp;
+ uint64_t pc;
+ uint64_t pstate;
+};
+
+#define TARGET_HW_MACHINE "arm64"
+#define TARGET_HW_MACHINE_ARCH "aarch64"
+
+#endif /* BSD_USER_AARCH64_TARGET_SYSCALL_H */
--
2.34.1
© 2016 - 2024 Red Hat, Inc.