diff options
Diffstat (limited to 'bsd-user')
34 files changed, 1865 insertions, 155 deletions
diff --git a/bsd-user/aarch64/signal.c b/bsd-user/aarch64/signal.c new file mode 100644 index 0000000..6bc73a7 --- /dev/null +++ b/bsd-user/aarch64/signal.c @@ -0,0 +1,137 @@ +/* + * ARM AArch64 specific signal definitions 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/>. + */ +#include "qemu/osdep.h" + +#include "qemu.h" + +/* + * Compare to sendsig() in sys/arm64/arm64/exec_machdep.c + * Assumes that target stack frame memory is locked. + */ +abi_long set_sigtramp_args(CPUARMState *regs, int sig, + struct target_sigframe *frame, + abi_ulong frame_addr, + struct target_sigaction *ka) +{ + /* + * Arguments to signal handler: + * x0 = signal number + * x1 = siginfo pointer + * x2 = ucontext pointer + * pc/elr = signal handler pointer + * sp = sigframe struct pointer + * lr = sigtramp at base of user stack + */ + + regs->xregs[0] = sig; + regs->xregs[1] = frame_addr + + offsetof(struct target_sigframe, sf_si); + regs->xregs[2] = frame_addr + + offsetof(struct target_sigframe, sf_uc); + + regs->pc = ka->_sa_handler; + regs->xregs[TARGET_REG_SP] = frame_addr; + regs->xregs[TARGET_REG_LR] = TARGET_PS_STRINGS - TARGET_SZSIGCODE; + + return 0; +} + +/* + * Compare to get_mcontext() in arm64/arm64/machdep.c + * Assumes that the memory is locked if mcp points to user memory. + */ +abi_long get_mcontext(CPUARMState *regs, target_mcontext_t *mcp, int flags) +{ + int err = 0, i; + uint64_t *gr = mcp->mc_gpregs.gp_x; + + mcp->mc_gpregs.gp_spsr = pstate_read(regs); + if (flags & TARGET_MC_GET_CLEAR_RET) { + gr[0] = 0UL; + mcp->mc_gpregs.gp_spsr &= ~CPSR_C; + } else { + gr[0] = tswap64(regs->xregs[0]); + } + + for (i = 1; i < 30; i++) { + gr[i] = tswap64(regs->xregs[i]); + } + + mcp->mc_gpregs.gp_sp = tswap64(regs->xregs[TARGET_REG_SP]); + mcp->mc_gpregs.gp_lr = tswap64(regs->xregs[TARGET_REG_LR]); + mcp->mc_gpregs.gp_elr = tswap64(regs->pc); + + /* XXX FP? */ + + return err; +} + +/* + * Compare to arm64/arm64/exec_machdep.c sendsig() + * Assumes that the memory is locked if frame points to user memory. + */ +abi_long setup_sigframe_arch(CPUARMState *env, abi_ulong frame_addr, + struct target_sigframe *frame, int flags) +{ + target_mcontext_t *mcp = &frame->sf_uc.uc_mcontext; + + get_mcontext(env, mcp, flags); + return 0; +} + +/* + * Compare to set_mcontext() in arm64/arm64/machdep.c + * Assumes that the memory is locked if frame points to user memory. + */ +abi_long set_mcontext(CPUARMState *regs, target_mcontext_t *mcp, int srflag) +{ + int err = 0, i; + const uint64_t *gr = mcp->mc_gpregs.gp_x; + + for (i = 0; i < 30; i++) { + regs->xregs[i] = tswap64(gr[i]); + } + + regs->xregs[TARGET_REG_SP] = tswap64(mcp->mc_gpregs.gp_sp); + regs->xregs[TARGET_REG_LR] = tswap64(mcp->mc_gpregs.gp_lr); + regs->pc = mcp->mc_gpregs.gp_elr; + pstate_write(regs, mcp->mc_gpregs.gp_spsr); + + /* XXX FP? */ + + return err; +} + +/* Compare to sys_sigreturn() in arm64/arm64/machdep.c */ +abi_long get_ucontext_sigreturn(CPUARMState *regs, abi_ulong target_sf, + abi_ulong *target_uc) +{ + uint32_t pstate = pstate_read(regs); + + *target_uc = 0; + + if ((pstate & PSTATE_M) != PSTATE_MODE_EL0t || + (pstate & (PSTATE_F | PSTATE_I | PSTATE_A | PSTATE_D)) != 0) { + return -TARGET_EINVAL; + } + + *target_uc = target_sf; + + return 0; +} diff --git a/bsd-user/aarch64/target.h b/bsd-user/aarch64/target.h new file mode 100644 index 0000000..702aeb7 --- /dev/null +++ b/bsd-user/aarch64/target.h @@ -0,0 +1,20 @@ +/* + * Aarch64 general target stuff that's common to all aarch details + * + * Copyright (c) 2022 M. Warner Losh <imp@bsdimp.com> + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef TARGET_H +#define TARGET_H + +/* + * aaarch64 ABI does not 'lump' the registers for 64-bit args. + */ +static inline bool regpairs_aligned(void *cpu_env) +{ + return false; +} + +#endif /* TARGET_H */ diff --git a/bsd-user/aarch64/target_arch.h b/bsd-user/aarch64/target_arch.h new file mode 100644 index 0000000..4815a56 --- /dev/null +++ b/bsd-user/aarch64/target_arch.h @@ -0,0 +1,29 @@ +/* + * ARM AArch64 specific prototypes 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 TARGET_ARCH_H +#define TARGET_ARCH_H + +#include "qemu.h" +#include "target/arm/cpu-features.h" + +void target_cpu_set_tls(CPUARMState *env, target_ulong newtls); +target_ulong target_cpu_get_tls(CPUARMState *env); + +#endif /* TARGET_ARCH_H */ diff --git a/bsd-user/aarch64/target_arch_cpu.c b/bsd-user/aarch64/target_arch_cpu.c new file mode 100644 index 0000000..b2fa59e --- /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 0000000..b288e0d --- /dev/null +++ b/bsd-user/aarch64/target_arch_cpu.h @@ -0,0 +1,189 @@ +/* + * 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 "signal-common.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; + 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() + */ + if (ret >= 0) { + env->CF = 0; + env->xregs[0] = ret; + } else if (ret == -TARGET_ERESTART) { + env->pc -= 4; + break; + } else if (ret != -TARGET_EJUSTRETURN) { + env->CF = 1; + env->xregs[0] = -ret; + } + 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_arch_elf.h b/bsd-user/aarch64/target_arch_elf.h new file mode 100644 index 0000000..cc87f47 --- /dev/null +++ b/bsd-user/aarch64/target_arch_elf.h @@ -0,0 +1,163 @@ +/* + * ARM AArch64 ELF definitions for bsd-user + * + * Copyright (c) 2015 Stacey D. 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_ELF_H +#define TARGET_ARCH_ELF_H + +#define ELF_START_MMAP 0x80000000 +#define ELF_ET_DYN_LOAD_ADDR 0x100000 + +#define elf_check_arch(x) ((x) == EM_AARCH64) + +#define ELF_CLASS ELFCLASS64 +#define ELF_DATA ELFDATA2LSB +#define ELF_ARCH EM_AARCH64 + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +enum { + ARM_HWCAP_A64_FP = 1 << 0, + ARM_HWCAP_A64_ASIMD = 1 << 1, + ARM_HWCAP_A64_EVTSTRM = 1 << 2, + ARM_HWCAP_A64_AES = 1 << 3, + ARM_HWCAP_A64_PMULL = 1 << 4, + ARM_HWCAP_A64_SHA1 = 1 << 5, + ARM_HWCAP_A64_SHA2 = 1 << 6, + ARM_HWCAP_A64_CRC32 = 1 << 7, + ARM_HWCAP_A64_ATOMICS = 1 << 8, + ARM_HWCAP_A64_FPHP = 1 << 9, + ARM_HWCAP_A64_ASIMDHP = 1 << 10, + ARM_HWCAP_A64_CPUID = 1 << 11, + ARM_HWCAP_A64_ASIMDRDM = 1 << 12, + ARM_HWCAP_A64_JSCVT = 1 << 13, + ARM_HWCAP_A64_FCMA = 1 << 14, + ARM_HWCAP_A64_LRCPC = 1 << 15, + ARM_HWCAP_A64_DCPOP = 1 << 16, + ARM_HWCAP_A64_SHA3 = 1 << 17, + ARM_HWCAP_A64_SM3 = 1 << 18, + ARM_HWCAP_A64_SM4 = 1 << 19, + ARM_HWCAP_A64_ASIMDDP = 1 << 20, + ARM_HWCAP_A64_SHA512 = 1 << 21, + ARM_HWCAP_A64_SVE = 1 << 22, + ARM_HWCAP_A64_ASIMDFHM = 1 << 23, + ARM_HWCAP_A64_DIT = 1 << 24, + ARM_HWCAP_A64_USCAT = 1 << 25, + ARM_HWCAP_A64_ILRCPC = 1 << 26, + ARM_HWCAP_A64_FLAGM = 1 << 27, + ARM_HWCAP_A64_SSBS = 1 << 28, + ARM_HWCAP_A64_SB = 1 << 29, + ARM_HWCAP_A64_PACA = 1 << 30, + ARM_HWCAP_A64_PACG = 1UL << 31, + + ARM_HWCAP2_A64_DCPODP = 1 << 0, + ARM_HWCAP2_A64_SVE2 = 1 << 1, + ARM_HWCAP2_A64_SVEAES = 1 << 2, + ARM_HWCAP2_A64_SVEPMULL = 1 << 3, + ARM_HWCAP2_A64_SVEBITPERM = 1 << 4, + ARM_HWCAP2_A64_SVESHA3 = 1 << 5, + ARM_HWCAP2_A64_SVESM4 = 1 << 6, + ARM_HWCAP2_A64_FLAGM2 = 1 << 7, + ARM_HWCAP2_A64_FRINT = 1 << 8, + ARM_HWCAP2_A64_SVEI8MM = 1 << 9, + ARM_HWCAP2_A64_SVEF32MM = 1 << 10, + ARM_HWCAP2_A64_SVEF64MM = 1 << 11, + ARM_HWCAP2_A64_SVEBF16 = 1 << 12, + ARM_HWCAP2_A64_I8MM = 1 << 13, + ARM_HWCAP2_A64_BF16 = 1 << 14, + ARM_HWCAP2_A64_DGH = 1 << 15, + ARM_HWCAP2_A64_RNG = 1 << 16, + ARM_HWCAP2_A64_BTI = 1 << 17, + ARM_HWCAP2_A64_MTE = 1 << 18, +}; + +#define ELF_HWCAP get_elf_hwcap() +#define ELF_HWCAP2 get_elf_hwcap2() + +#define GET_FEATURE_ID(feat, hwcap) \ + do { if (cpu_isar_feature(feat, cpu)) { hwcaps |= hwcap; } } while (0) + +static uint32_t get_elf_hwcap(void) +{ + ARMCPU *cpu = ARM_CPU(thread_cpu); + uint32_t hwcaps = 0; + + hwcaps |= ARM_HWCAP_A64_FP; + hwcaps |= ARM_HWCAP_A64_ASIMD; + hwcaps |= ARM_HWCAP_A64_CPUID; + + /* probe for the extra features */ + + GET_FEATURE_ID(aa64_aes, ARM_HWCAP_A64_AES); + GET_FEATURE_ID(aa64_pmull, ARM_HWCAP_A64_PMULL); + GET_FEATURE_ID(aa64_sha1, ARM_HWCAP_A64_SHA1); + GET_FEATURE_ID(aa64_sha256, ARM_HWCAP_A64_SHA2); + GET_FEATURE_ID(aa64_sha512, ARM_HWCAP_A64_SHA512); + GET_FEATURE_ID(aa64_crc32, ARM_HWCAP_A64_CRC32); + GET_FEATURE_ID(aa64_sha3, ARM_HWCAP_A64_SHA3); + GET_FEATURE_ID(aa64_sm3, ARM_HWCAP_A64_SM3); + GET_FEATURE_ID(aa64_sm4, ARM_HWCAP_A64_SM4); + GET_FEATURE_ID(aa64_fp16, ARM_HWCAP_A64_FPHP | ARM_HWCAP_A64_ASIMDHP); + GET_FEATURE_ID(aa64_atomics, ARM_HWCAP_A64_ATOMICS); + GET_FEATURE_ID(aa64_rdm, ARM_HWCAP_A64_ASIMDRDM); + GET_FEATURE_ID(aa64_dp, ARM_HWCAP_A64_ASIMDDP); + GET_FEATURE_ID(aa64_fcma, ARM_HWCAP_A64_FCMA); + GET_FEATURE_ID(aa64_sve, ARM_HWCAP_A64_SVE); + GET_FEATURE_ID(aa64_pauth, ARM_HWCAP_A64_PACA | ARM_HWCAP_A64_PACG); + GET_FEATURE_ID(aa64_fhm, ARM_HWCAP_A64_ASIMDFHM); + GET_FEATURE_ID(aa64_jscvt, ARM_HWCAP_A64_JSCVT); + GET_FEATURE_ID(aa64_sb, ARM_HWCAP_A64_SB); + GET_FEATURE_ID(aa64_condm_4, ARM_HWCAP_A64_FLAGM); + GET_FEATURE_ID(aa64_dcpop, ARM_HWCAP_A64_DCPOP); + GET_FEATURE_ID(aa64_rcpc_8_3, ARM_HWCAP_A64_LRCPC); + GET_FEATURE_ID(aa64_rcpc_8_4, ARM_HWCAP_A64_ILRCPC); + + return hwcaps; +} + +static uint32_t get_elf_hwcap2(void) +{ + ARMCPU *cpu = ARM_CPU(thread_cpu); + uint32_t hwcaps = 0; + + GET_FEATURE_ID(aa64_dcpodp, ARM_HWCAP2_A64_DCPODP); + GET_FEATURE_ID(aa64_sve2, ARM_HWCAP2_A64_SVE2); + GET_FEATURE_ID(aa64_sve2_aes, ARM_HWCAP2_A64_SVEAES); + GET_FEATURE_ID(aa64_sve2_pmull128, ARM_HWCAP2_A64_SVEPMULL); + GET_FEATURE_ID(aa64_sve2_bitperm, ARM_HWCAP2_A64_SVEBITPERM); + GET_FEATURE_ID(aa64_sve2_sha3, ARM_HWCAP2_A64_SVESHA3); + GET_FEATURE_ID(aa64_sve2_sm4, ARM_HWCAP2_A64_SVESM4); + GET_FEATURE_ID(aa64_condm_5, ARM_HWCAP2_A64_FLAGM2); + GET_FEATURE_ID(aa64_frint, ARM_HWCAP2_A64_FRINT); + GET_FEATURE_ID(aa64_sve_i8mm, ARM_HWCAP2_A64_SVEI8MM); + GET_FEATURE_ID(aa64_sve_f32mm, ARM_HWCAP2_A64_SVEF32MM); + GET_FEATURE_ID(aa64_sve_f64mm, ARM_HWCAP2_A64_SVEF64MM); + GET_FEATURE_ID(aa64_sve_bf16, ARM_HWCAP2_A64_SVEBF16); + GET_FEATURE_ID(aa64_i8mm, ARM_HWCAP2_A64_I8MM); + GET_FEATURE_ID(aa64_bf16, ARM_HWCAP2_A64_BF16); + GET_FEATURE_ID(aa64_rndr, ARM_HWCAP2_A64_RNG); + GET_FEATURE_ID(aa64_bti, ARM_HWCAP2_A64_BTI); + GET_FEATURE_ID(aa64_mte, ARM_HWCAP2_A64_MTE); + + return hwcaps; +} + +#undef GET_FEATURE_ID + +#endif /* TARGET_ARCH_ELF_H */ diff --git a/bsd-user/aarch64/target_arch_reg.h b/bsd-user/aarch64/target_arch_reg.h new file mode 100644 index 0000000..b53302e --- /dev/null +++ b/bsd-user/aarch64/target_arch_reg.h @@ -0,0 +1,56 @@ +/* + * FreeBSD arm64 register structures + * + * Copyright (c) 2015 Stacey Son + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef TARGET_ARCH_REG_H +#define TARGET_ARCH_REG_H + +/* See sys/arm64/include/reg.h */ +typedef struct target_reg { + uint64_t x[30]; + uint64_t lr; + uint64_t sp; + uint64_t elr; + uint64_t spsr; +} target_reg_t; + +typedef struct target_fpreg { + Int128 fp_q[32]; + uint32_t fp_sr; + uint32_t fp_cr; +} target_fpreg_t; + +#define tswapreg(ptr) tswapal(ptr) + +static inline void target_copy_regs(target_reg_t *regs, CPUARMState *env) +{ + int i; + + for (i = 0; i < 30; i++) { + regs->x[i] = tswapreg(env->xregs[i]); + } + regs->lr = tswapreg(env->xregs[30]); + regs->sp = tswapreg(env->xregs[31]); + regs->elr = tswapreg(env->pc); + regs->spsr = tswapreg(pstate_read(env)); +} + +#undef tswapreg + +#endif /* TARGET_ARCH_REG_H */ diff --git a/bsd-user/aarch64/target_arch_signal.h b/bsd-user/aarch64/target_arch_signal.h new file mode 100644 index 0000000..b72ba7a --- /dev/null +++ b/bsd-user/aarch64/target_arch_signal.h @@ -0,0 +1,82 @@ +/* + * ARM AArch64 specific signal definitions 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 TARGET_ARCH_SIGNAL_H +#define TARGET_ARCH_SIGNAL_H + +#include "cpu.h" + +#define TARGET_REG_X0 0 +#define TARGET_REG_X30 30 +#define TARGET_REG_X31 31 +#define TARGET_REG_LR TARGET_REG_X30 +#define TARGET_REG_SP TARGET_REG_X31 + +#define TARGET_INSN_SIZE 4 /* arm64 instruction size */ + +/* Size of the signal trampolin code. See _sigtramp(). */ +#define TARGET_SZSIGCODE ((abi_ulong)(9 * TARGET_INSN_SIZE)) + +/* compare to sys/arm64/include/_limits.h */ +#define TARGET_MINSIGSTKSZ (1024 * 4) /* min sig stack size */ +#define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768) /* recommended size */ + +/* struct __mcontext in sys/arm64/include/ucontext.h */ + +struct target_gpregs { + uint64_t gp_x[30]; + uint64_t gp_lr; + uint64_t gp_sp; + uint64_t gp_elr; + uint32_t gp_spsr; + uint32_t gp_pad; +}; + +struct target_fpregs { + Int128 fp_q[32]; + uint32_t fp_sr; + uint32_t fp_cr; + uint32_t fp_flags; + uint32_t fp_pad; +}; + +struct target__mcontext { + struct target_gpregs mc_gpregs; + struct target_fpregs mc_fpregs; + uint32_t mc_flags; +#define TARGET_MC_FP_VALID 0x1 + uint32_t mc_pad; + uint64_t mc_spare[8]; +}; + +typedef struct target__mcontext target_mcontext_t; + +#define TARGET_MCONTEXT_SIZE 880 +#define TARGET_UCONTEXT_SIZE 960 + +#include "target_os_ucontext.h" + +struct target_sigframe { + target_siginfo_t sf_si; /* saved siginfo */ + target_ucontext_t sf_uc; /* saved ucontext */ +}; + +#define TARGET_SIGSTACK_ALIGN 16 + +#endif /* TARGET_ARCH_SIGNAL_H */ diff --git a/bsd-user/aarch64/target_arch_sigtramp.h b/bsd-user/aarch64/target_arch_sigtramp.h new file mode 100644 index 0000000..8cdd33b --- /dev/null +++ b/bsd-user/aarch64/target_arch_sigtramp.h @@ -0,0 +1,48 @@ +/* + * ARM AArch64 sigcode 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 TARGET_ARCH_SIGTRAMP_H +#define TARGET_ARCH_SIGTRAMP_H + +/* Compare to ENTRY(sigcode) in arm64/arm64/locore.S */ +static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc, + unsigned sys_sigreturn) +{ + int i; + uint32_t sys_exit = TARGET_FREEBSD_NR_exit; + + uint32_t sigtramp_code[] = { + /* 1 */ 0x910003e0, /* mov x0, sp */ + /* 2 */ 0x91000000 + (sigf_uc << 10), /* add x0, x0, #SIGF_UC */ + /* 3 */ 0xd2800000 + (sys_sigreturn << 5) + 0x8, /* mov x8, #SYS_sigreturn */ + /* 4 */ 0xd4000001, /* svc #0 */ + /* 5 */ 0xd2800028 + (sys_exit << 5) + 0x8, /* mov x8, #SYS_exit */ + /* 6 */ 0xd4000001, /* svc #0 */ + /* 7 */ 0x17fffffc, /* b -4 */ + /* 8 */ sys_sigreturn, + /* 9 */ sys_exit + }; + + for (i = 0; i < 9; i++) { + tswap32s(&sigtramp_code[i]); + } + + return memcpy_to_target(offset, sigtramp_code, TARGET_SZSIGCODE); +} +#endif /* TARGET_ARCH_SIGTRAMP_H */ diff --git a/bsd-user/aarch64/target_arch_sysarch.h b/bsd-user/aarch64/target_arch_sysarch.h new file mode 100644 index 0000000..b003015 --- /dev/null +++ b/bsd-user/aarch64/target_arch_sysarch.h @@ -0,0 +1,42 @@ +/* + * ARM AArch64 sysarch() system call emulation for bsd-user. + * + * Copyright (c) 2015 <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 TARGET_ARCH_SYSARCH_H +#define TARGET_ARCH_SYSARCH_H + +#include "target_syscall.h" +#include "target_arch.h" + +/* See sysarch() in sys/arm64/arm64/sys_machdep.c */ +static inline abi_long do_freebsd_arch_sysarch(CPUARMState *env, int op, + abi_ulong parms) +{ + int ret = -TARGET_EOPNOTSUPP; + + fprintf(stderr, "sysarch"); + return ret; +} + +static inline void do_freebsd_arch_print_sysarch( + const struct syscallname *name, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6) +{ +} + +#endif /* TARGET_ARCH_SYSARCH_H */ diff --git a/bsd-user/aarch64/target_arch_thread.h b/bsd-user/aarch64/target_arch_thread.h new file mode 100644 index 0000000..4c911e6 --- /dev/null +++ b/bsd-user/aarch64/target_arch_thread.h @@ -0,0 +1,61 @@ +/* + * ARM AArch64 thread support 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 TARGET_ARCH_THREAD_H +#define TARGET_ARCH_THREAD_H + +/* Compare to arm64/arm64/vm_machdep.c cpu_set_upcall_kse() */ +static inline void target_thread_set_upcall(CPUARMState *regs, abi_ulong entry, + abi_ulong arg, abi_ulong stack_base, abi_ulong stack_size) +{ + abi_ulong sp; + + /* + * Make sure the stack is properly aligned. + * arm64/include/param.h (STACKLIGN() macro) + */ + sp = ROUND_DOWN(stack_base + stack_size, 16); + + /* sp = stack base */ + regs->xregs[31] = sp; + /* pc = start function entry */ + regs->pc = entry; + /* r0 = arg */ + regs->xregs[0] = arg; + + +} + +static inline void target_thread_init(struct target_pt_regs *regs, + struct image_info *infop) +{ + abi_long stack = infop->start_stack; + + /* + * Make sure the stack is properly aligned. + * arm64/include/param.h (STACKLIGN() macro) + */ + + memset(regs, 0, sizeof(*regs)); + regs->regs[0] = infop->start_stack; + regs->pc = infop->entry; + regs->sp = ROUND_DOWN(stack, 16); +} + +#endif /* TARGET_ARCH_THREAD_H */ diff --git a/bsd-user/aarch64/target_arch_vmparam.h b/bsd-user/aarch64/target_arch_vmparam.h new file mode 100644 index 0000000..0c35491 --- /dev/null +++ b/bsd-user/aarch64/target_arch_vmparam.h @@ -0,0 +1,74 @@ +/* + * ARM AArch64 VM parameters definitions 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 TARGET_ARCH_VMPARAM_H +#define TARGET_ARCH_VMPARAM_H + +#include "cpu.h" + +/** + * FreeBSD/arm64 Address space layout. + * + * ARMv8 implements up to a 48 bit virtual address space. The address space is + * split into 2 regions at each end of the 64 bit address space, with an + * out of range "hole" in the middle. + * + * We limit the size of the two spaces to 39 bits each. + * + * Upper region: 0xffffffffffffffff + * 0xffffff8000000000 + * + * Hole: 0xffffff7fffffffff + * 0x0000008000000000 + * + * Lower region: 0x0000007fffffffff + * 0x0000000000000000 + * + * The upper region for the kernel, and the lower region for userland. + */ + + +/* compare to sys/arm64/include/vmparam.h */ +#define TARGET_MAXTSIZ (1 * GiB) /* max text size */ +#define TARGET_DFLDSIZ (128 * MiB) /* initial data size limit */ +#define TARGET_MAXDSIZ (1 * GiB) /* max data size */ +#define TARGET_DFLSSIZ (128 * MiB) /* initial stack size limit */ +#define TARGET_MAXSSIZ (1 * GiB) /* max stack size */ +#define TARGET_SGROWSIZ (128 * KiB) /* amount to grow stack */ + + /* KERNBASE - 512 MB */ +#define TARGET_VM_MAXUSER_ADDRESS (0x00007fffff000000ULL - (512 * MiB)) +#define TARGET_USRSTACK TARGET_VM_MAXUSER_ADDRESS + +static inline abi_ulong get_sp_from_cpustate(CPUARMState *state) +{ + return state->xregs[31]; /* sp */ +} + +static inline void set_second_rval(CPUARMState *state, abi_ulong retval2) +{ + state->xregs[1] = retval2; /* XXX not really used on 64-bit arch */ +} + +static inline abi_ulong get_second_rval(CPUARMState *state) +{ + return state->xregs[1]; +} + +#endif /* TARGET_ARCH_VMPARAM_H */ diff --git a/bsd-user/aarch64/target_syscall.h b/bsd-user/aarch64/target_syscall.h new file mode 100644 index 0000000..08ae913 --- /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 */ diff --git a/bsd-user/arm/target_arch_signal.h b/bsd-user/arm/target_arch_signal.h index 02b2b33..10f96b8 100644 --- a/bsd-user/arm/target_arch_signal.h +++ b/bsd-user/arm/target_arch_signal.h @@ -86,4 +86,6 @@ struct target_sigframe { target_mcontext_vfp_t sf_vfp; /* actual saved VFP context */ }; +#define TARGET_SIGSTACK_ALIGN 8 + #endif /* TARGET_ARCH_SIGNAL_H */ diff --git a/bsd-user/freebsd/os-proc.c b/bsd-user/freebsd/os-proc.c index e0203e2..bf993f1 100644 --- a/bsd-user/freebsd/os-proc.c +++ b/bsd-user/freebsd/os-proc.c @@ -27,64 +27,12 @@ struct kinfo_proc; #include "qemu.h" /* - * Get the filename for the given file descriptor. - * Note that this may return NULL (fail) if no longer cached in the kernel. - */ -static char * -get_filename_from_fd(pid_t pid, int fd, char *filename, size_t len) -{ - char *ret = NULL; - unsigned int cnt; - struct procstat *procstat = NULL; - struct kinfo_proc *kp = NULL; - struct filestat_list *head = NULL; - struct filestat *fst; - - procstat = procstat_open_sysctl(); - if (procstat == NULL) { - goto out; - } - - kp = procstat_getprocs(procstat, KERN_PROC_PID, pid, &cnt); - if (kp == NULL) { - goto out; - } - - head = procstat_getfiles(procstat, kp, 0); - if (head == NULL) { - goto out; - } - - STAILQ_FOREACH(fst, head, next) { - if (fd == fst->fs_fd) { - if (fst->fs_path != NULL) { - (void)strlcpy(filename, fst->fs_path, len); - ret = filename; - } - break; - } - } - -out: - if (head != NULL) { - procstat_freefiles(procstat, head); - } - if (kp != NULL) { - procstat_freeprocs(procstat, kp); - } - if (procstat != NULL) { - procstat_close(procstat); - } - return ret; -} - -/* * execve/fexecve */ abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp, abi_ulong guest_envp, int do_fexec) { - char **argp, **envp, **qargp, **qarg1, **qarg0, **qargend; + char **argp, **envp, **qarg0; int argc, envc; abi_ulong gp; abi_ulong addr; @@ -117,9 +65,7 @@ abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp, qarg0 = argp = g_new0(char *, argc + 9); /* save the first argument for the emulator */ *argp++ = (char *)getprogname(); - qargp = argp; *argp++ = (char *)getprogname(); - qarg1 = argp; envp = g_new0(char *, envc + 1); for (gp = guest_argp, q = argp; gp; gp += sizeof(abi_ulong), q++) { if (get_user_ual(addr, gp)) { @@ -137,7 +83,6 @@ abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp, total_size += strlen(*q) + 1; } *q++ = NULL; - qargend = q; for (gp = guest_envp, q = envp; gp; gp += sizeof(abi_ulong), q++) { if (get_user_ual(addr, gp)) { @@ -166,71 +111,14 @@ abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp, } if (do_fexec) { - if (((int)path_or_fd > 0 && - is_target_elf_binary((int)path_or_fd)) == 1) { - char execpath[PATH_MAX]; - - /* - * The executable is an elf binary for the target - * arch. execve() it using the emulator if we can - * determine the filename path from the fd. - */ - if (get_filename_from_fd(getpid(), (int)path_or_fd, execpath, - sizeof(execpath)) != NULL) { - memmove(qarg1 + 2, qarg1, (qargend - qarg1) * sizeof(*qarg1)); - qarg1[1] = qarg1[0]; - qarg1[0] = (char *)"-0"; - qarg1 += 2; - qargend += 2; - *qarg1 = execpath; -#ifndef DONT_INHERIT_INTERP_PREFIX - memmove(qarg1 + 2, qarg1, (qargend - qarg1) * sizeof(*qarg1)); - *qarg1++ = (char *)"-L"; - *qarg1++ = (char *)interp_prefix; -#endif - ret = get_errno(execve(qemu_proc_pathname, qargp, envp)); - } else { - /* Getting the filename path failed. */ - ret = -TARGET_EBADF; - goto execve_end; - } - } else { - ret = get_errno(fexecve((int)path_or_fd, argp, envp)); - } + ret = get_errno(fexecve((int)path_or_fd, argp, envp)); } else { - int fd; - p = lock_user_string(path_or_fd); if (p == NULL) { ret = -TARGET_EFAULT; goto execve_end; } - - /* - * Check the header and see if it a target elf binary. If so - * then execute using qemu user mode emulator. - */ - fd = open(p, O_RDONLY | O_CLOEXEC); - if (fd > 0 && is_target_elf_binary(fd) == 1) { - close(fd); - /* execve() as a target binary using emulator. */ - memmove(qarg1 + 2, qarg1, (qargend - qarg1) * sizeof(*qarg1)); - qarg1[1] = qarg1[0]; - qarg1[0] = (char *)"-0"; - qarg1 += 2; - qargend += 2; - *qarg1 = (char *)p; -#ifndef DONT_INHERIT_INTERP_PREFIX - memmove(qarg1 + 2, qarg1, (qargend - qarg1) * sizeof(*qarg1)); - *qarg1++ = (char *)"-L"; - *qarg1++ = (char *)interp_prefix; -#endif - ret = get_errno(execve(qemu_proc_pathname, qargp, envp)); - } else { - close(fd); - /* Execve() as a host native binary. */ - ret = get_errno(execve(p, argp, envp)); - } + ret = get_errno(execve(p, argp, envp)); unlock_user(p, path_or_fd, 0); } diff --git a/bsd-user/i386/target_arch_signal.h b/bsd-user/i386/target_arch_signal.h index 279dadc..2c14153 100644 --- a/bsd-user/i386/target_arch_signal.h +++ b/bsd-user/i386/target_arch_signal.h @@ -88,4 +88,6 @@ struct target_sigframe { uint32_t __spare__[2]; }; +#define TARGET_SIGSTACK_ALIGN 8 + #endif /* TARGET_ARCH_SIGNAL_H */ diff --git a/bsd-user/main.c b/bsd-user/main.c index dcad266..cc980e6 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -35,6 +35,7 @@ #include "qemu/path.h" #include "qemu/help_option.h" #include "qemu/module.h" +#include "qemu/plugin.h" #include "exec/exec-all.h" #include "user/guest-base.h" #include "tcg/startup.h" @@ -90,7 +91,6 @@ unsigned long reserved_va; const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX; const char *qemu_uname_release; -char qemu_proc_pathname[PATH_MAX]; /* full path to exeutable */ unsigned long target_maxtsiz = TARGET_MAXTSIZ; /* max text size */ unsigned long target_dfldsiz = TARGET_DFLDSIZ; /* initial data size limit */ @@ -104,8 +104,9 @@ unsigned long target_sgrowsiz = TARGET_SGROWSIZ; /* amount to grow stack */ void fork_start(void) { start_exclusive(); - cpu_list_lock(); mmap_fork_start(); + cpu_list_lock(); + qemu_plugin_user_prefork_lock(); gdbserver_fork_start(); } @@ -113,31 +114,31 @@ void fork_end(pid_t pid) { bool child = pid == 0; + qemu_plugin_user_postfork(child); + mmap_fork_end(child); if (child) { CPUState *cpu, *next_cpu; /* - * Child processes created by fork() only have a single thread. Discard - * information about the parent threads. + * Child processes created by fork() only have a single thread. + * Discard information about the parent threads. */ CPU_FOREACH_SAFE(cpu, next_cpu) { if (cpu != thread_cpu) { QTAILQ_REMOVE_RCU(&cpus_queue, cpu, node); } } - mmap_fork_end(child); - /* - * qemu_init_cpu_list() takes care of reinitializing the exclusive - * state, so we don't need to end_exclusive() here. - */ qemu_init_cpu_list(); get_task_state(thread_cpu)->ts_tid = qemu_get_thread_id(); - gdbserver_fork_end(thread_cpu, pid); } else { - mmap_fork_end(child); cpu_list_unlock(); - gdbserver_fork_end(thread_cpu, pid); - end_exclusive(); } + gdbserver_fork_end(thread_cpu, pid); + /* + * qemu_init_cpu_list() reinitialized the child exclusive state, but we + * also need to keep current_cpu consistent, so call end_exclusive() for + * both child and parent. + */ + end_exclusive(); } void cpu_loop(CPUArchState *env) @@ -247,22 +248,6 @@ adjust_ssize(void) setrlimit(RLIMIT_STACK, &rl); } -static void save_proc_pathname(char *argv0) -{ - int mib[4]; - size_t len; - - mib[0] = CTL_KERN; - mib[1] = KERN_PROC; - mib[2] = KERN_PROC_PATHNAME; - mib[3] = -1; - - len = sizeof(qemu_proc_pathname); - if (sysctl(mib, 4, qemu_proc_pathname, &len, NULL, 0)) { - perror("sysctl"); - } -} - int main(int argc, char **argv) { const char *filename; @@ -292,7 +277,6 @@ int main(int argc, char **argv) usage(); } - save_proc_pathname(argv[0]); error_init(argv[0]); module_call_init(MODULE_INIT_TRACE); diff --git a/bsd-user/mmap.c b/bsd-user/mmap.c index f3a4f17..775e905 100644 --- a/bsd-user/mmap.c +++ b/bsd-user/mmap.c @@ -129,6 +129,40 @@ error: } /* + * Perform a pread on behalf of target_mmap. We can reach EOF, we can be + * interrupted by signals, and in general there's no good error return path. + * If @zero, zero the rest of the block at EOF. + * Return true on success. + */ +static bool mmap_pread(int fd, void *p, size_t len, off_t offset, bool zero) +{ + while (1) { + ssize_t r = pread(fd, p, len, offset); + + if (likely(r == len)) { + /* Complete */ + return true; + } + if (r == 0) { + /* EOF */ + if (zero) { + memset(p, 0, len); + } + return true; + } + if (r > 0) { + /* Short read */ + p += r; + len -= r; + offset += r; + } else if (errno != EINTR) { + /* Error */ + return false; + } + } +} + +/* * map an incomplete host page * * mmap_frag can be called with a valid fd, if flags doesn't contain one of @@ -190,7 +224,7 @@ static int mmap_frag(abi_ulong real_start, mprotect(host_start, qemu_host_page_size, prot1 | PROT_WRITE); /* read the corresponding file data */ - if (pread(fd, g2h_untagged(start), end - start, offset) == -1) { + if (!mmap_pread(fd, g2h_untagged(start), end - start, offset, true)) { return -1; } @@ -565,7 +599,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, -1, 0); if (retaddr == -1) goto fail; - if (pread(fd, g2h_untagged(start), len, offset) == -1) { + if (!mmap_pread(fd, g2h_untagged(start), len, offset, false)) { goto fail; } if (!(prot & PROT_WRITE)) { diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index 9d2fc71..3736c41 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -17,6 +17,9 @@ #ifndef QEMU_H #define QEMU_H +#include <sys/param.h> + +#include "qemu/int128.h" #include "cpu.h" #include "qemu/units.h" #include "exec/cpu_ldst.h" diff --git a/bsd-user/riscv/signal.c b/bsd-user/riscv/signal.c new file mode 100644 index 0000000..10c940c --- /dev/null +++ b/bsd-user/riscv/signal.c @@ -0,0 +1,170 @@ +/* + * RISC-V signal definitions + * + * Copyright (c) 2019 Mark Corbin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ +#include "qemu/osdep.h" + +#include "qemu.h" + +/* + * Compare with sendsig() in riscv/riscv/exec_machdep.c + * Assumes that target stack frame memory is locked. + */ +abi_long +set_sigtramp_args(CPURISCVState *regs, int sig, struct target_sigframe *frame, + abi_ulong frame_addr, struct target_sigaction *ka) +{ + /* + * Arguments to signal handler: + * a0 (10) = signal number + * a1 (11) = siginfo pointer + * a2 (12) = ucontext pointer + * pc = signal pointer handler + * sp (2) = sigframe pointer + * ra (1) = sigtramp at base of user stack + */ + + regs->gpr[xA0] = sig; + regs->gpr[xA1] = frame_addr + + offsetof(struct target_sigframe, sf_si); + regs->gpr[xA2] = frame_addr + + offsetof(struct target_sigframe, sf_uc); + regs->pc = ka->_sa_handler; + regs->gpr[xSP] = frame_addr; + regs->gpr[xRA] = TARGET_PS_STRINGS - TARGET_SZSIGCODE; + return 0; +} + +/* + * Compare to riscv/riscv/exec_machdep.c sendsig() + * Assumes that the memory is locked if frame points to user memory. + */ +abi_long setup_sigframe_arch(CPURISCVState *env, abi_ulong frame_addr, + struct target_sigframe *frame, int flags) +{ + target_mcontext_t *mcp = &frame->sf_uc.uc_mcontext; + + get_mcontext(env, mcp, flags); + return 0; +} + +/* + * Compare with get_mcontext() in riscv/riscv/machdep.c + * Assumes that the memory is locked if mcp points to user memory. + */ +abi_long get_mcontext(CPURISCVState *regs, target_mcontext_t *mcp, + int flags) +{ + + mcp->mc_gpregs.gp_t[0] = tswap64(regs->gpr[5]); + mcp->mc_gpregs.gp_t[1] = tswap64(regs->gpr[6]); + mcp->mc_gpregs.gp_t[2] = tswap64(regs->gpr[7]); + mcp->mc_gpregs.gp_t[3] = tswap64(regs->gpr[28]); + mcp->mc_gpregs.gp_t[4] = tswap64(regs->gpr[29]); + mcp->mc_gpregs.gp_t[5] = tswap64(regs->gpr[30]); + mcp->mc_gpregs.gp_t[6] = tswap64(regs->gpr[31]); + + mcp->mc_gpregs.gp_s[0] = tswap64(regs->gpr[8]); + mcp->mc_gpregs.gp_s[1] = tswap64(regs->gpr[9]); + mcp->mc_gpregs.gp_s[2] = tswap64(regs->gpr[18]); + mcp->mc_gpregs.gp_s[3] = tswap64(regs->gpr[19]); + mcp->mc_gpregs.gp_s[4] = tswap64(regs->gpr[20]); + mcp->mc_gpregs.gp_s[5] = tswap64(regs->gpr[21]); + mcp->mc_gpregs.gp_s[6] = tswap64(regs->gpr[22]); + mcp->mc_gpregs.gp_s[7] = tswap64(regs->gpr[23]); + mcp->mc_gpregs.gp_s[8] = tswap64(regs->gpr[24]); + mcp->mc_gpregs.gp_s[9] = tswap64(regs->gpr[25]); + mcp->mc_gpregs.gp_s[10] = tswap64(regs->gpr[26]); + mcp->mc_gpregs.gp_s[11] = tswap64(regs->gpr[27]); + + mcp->mc_gpregs.gp_a[0] = tswap64(regs->gpr[10]); + mcp->mc_gpregs.gp_a[1] = tswap64(regs->gpr[11]); + mcp->mc_gpregs.gp_a[2] = tswap64(regs->gpr[12]); + mcp->mc_gpregs.gp_a[3] = tswap64(regs->gpr[13]); + mcp->mc_gpregs.gp_a[4] = tswap64(regs->gpr[14]); + mcp->mc_gpregs.gp_a[5] = tswap64(regs->gpr[15]); + mcp->mc_gpregs.gp_a[6] = tswap64(regs->gpr[16]); + mcp->mc_gpregs.gp_a[7] = tswap64(regs->gpr[17]); + + if (flags & TARGET_MC_GET_CLEAR_RET) { + mcp->mc_gpregs.gp_a[0] = 0; /* a0 */ + mcp->mc_gpregs.gp_a[1] = 0; /* a1 */ + mcp->mc_gpregs.gp_t[0] = 0; /* clear syscall error */ + } + + mcp->mc_gpregs.gp_ra = tswap64(regs->gpr[1]); + mcp->mc_gpregs.gp_sp = tswap64(regs->gpr[2]); + mcp->mc_gpregs.gp_gp = tswap64(regs->gpr[3]); + mcp->mc_gpregs.gp_tp = tswap64(regs->gpr[4]); + mcp->mc_gpregs.gp_sepc = tswap64(regs->pc); + + return 0; +} + +/* Compare with set_mcontext() in riscv/riscv/exec_machdep.c */ +abi_long set_mcontext(CPURISCVState *regs, target_mcontext_t *mcp, + int srflag) +{ + + regs->gpr[5] = tswap64(mcp->mc_gpregs.gp_t[0]); + regs->gpr[6] = tswap64(mcp->mc_gpregs.gp_t[1]); + regs->gpr[7] = tswap64(mcp->mc_gpregs.gp_t[2]); + regs->gpr[28] = tswap64(mcp->mc_gpregs.gp_t[3]); + regs->gpr[29] = tswap64(mcp->mc_gpregs.gp_t[4]); + regs->gpr[30] = tswap64(mcp->mc_gpregs.gp_t[5]); + regs->gpr[31] = tswap64(mcp->mc_gpregs.gp_t[6]); + + regs->gpr[8] = tswap64(mcp->mc_gpregs.gp_s[0]); + regs->gpr[9] = tswap64(mcp->mc_gpregs.gp_s[1]); + regs->gpr[18] = tswap64(mcp->mc_gpregs.gp_s[2]); + regs->gpr[19] = tswap64(mcp->mc_gpregs.gp_s[3]); + regs->gpr[20] = tswap64(mcp->mc_gpregs.gp_s[4]); + regs->gpr[21] = tswap64(mcp->mc_gpregs.gp_s[5]); + regs->gpr[22] = tswap64(mcp->mc_gpregs.gp_s[6]); + regs->gpr[23] = tswap64(mcp->mc_gpregs.gp_s[7]); + regs->gpr[24] = tswap64(mcp->mc_gpregs.gp_s[8]); + regs->gpr[25] = tswap64(mcp->mc_gpregs.gp_s[9]); + regs->gpr[26] = tswap64(mcp->mc_gpregs.gp_s[10]); + regs->gpr[27] = tswap64(mcp->mc_gpregs.gp_s[11]); + + regs->gpr[10] = tswap64(mcp->mc_gpregs.gp_a[0]); + regs->gpr[11] = tswap64(mcp->mc_gpregs.gp_a[1]); + regs->gpr[12] = tswap64(mcp->mc_gpregs.gp_a[2]); + regs->gpr[13] = tswap64(mcp->mc_gpregs.gp_a[3]); + regs->gpr[14] = tswap64(mcp->mc_gpregs.gp_a[4]); + regs->gpr[15] = tswap64(mcp->mc_gpregs.gp_a[5]); + regs->gpr[16] = tswap64(mcp->mc_gpregs.gp_a[6]); + regs->gpr[17] = tswap64(mcp->mc_gpregs.gp_a[7]); + + + regs->gpr[1] = tswap64(mcp->mc_gpregs.gp_ra); + regs->gpr[2] = tswap64(mcp->mc_gpregs.gp_sp); + regs->gpr[3] = tswap64(mcp->mc_gpregs.gp_gp); + regs->gpr[4] = tswap64(mcp->mc_gpregs.gp_tp); + regs->pc = tswap64(mcp->mc_gpregs.gp_sepc); + + return 0; +} + +/* Compare with sys_sigreturn() in riscv/riscv/machdep.c */ +abi_long get_ucontext_sigreturn(CPURISCVState *regs, + abi_ulong target_sf, abi_ulong *target_uc) +{ + + *target_uc = target_sf; + return 0; +} diff --git a/bsd-user/riscv/target.h b/bsd-user/riscv/target.h new file mode 100644 index 0000000..036ddd1 --- /dev/null +++ b/bsd-user/riscv/target.h @@ -0,0 +1,20 @@ +/* + * Riscv64 general target stuff that's common to all aarch details + * + * Copyright (c) 2022 M. Warner Losh <imp@bsdimp.com> + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef TARGET_H +#define TARGET_H + +/* + * riscv64 ABI does not 'lump' the registers for 64-bit args. + */ +static inline bool regpairs_aligned(void *cpu_env) +{ + return false; +} + +#endif /* TARGET_H */ diff --git a/bsd-user/riscv/target_arch.h b/bsd-user/riscv/target_arch.h new file mode 100644 index 0000000..26ce07f --- /dev/null +++ b/bsd-user/riscv/target_arch.h @@ -0,0 +1,27 @@ +/* + * RISC-V specific prototypes + * + * Copyright (c) 2019 Mark Corbin <mark.corbin@embecsom.com> + * + * 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_H +#define TARGET_ARCH_H + +#include "qemu.h" + +void target_cpu_set_tls(CPURISCVState *env, target_ulong newtls); + +#endif /* TARGET_ARCH_H */ diff --git a/bsd-user/riscv/target_arch_cpu.c b/bsd-user/riscv/target_arch_cpu.c new file mode 100644 index 0000000..44e25d2 --- /dev/null +++ b/bsd-user/riscv/target_arch_cpu.c @@ -0,0 +1,29 @@ +/* + * RISC-V CPU related code + * + * Copyright (c) 2019 Mark Corbin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ +#include "qemu/osdep.h" + +#include "target_arch.h" + +#define TP_OFFSET 16 + +/* Compare with cpu_set_user_tls() in riscv/riscv/vm_machdep.c */ +void target_cpu_set_tls(CPURISCVState *env, target_ulong newtls) +{ + env->gpr[xTP] = newtls + TP_OFFSET; +} diff --git a/bsd-user/riscv/target_arch_cpu.h b/bsd-user/riscv/target_arch_cpu.h new file mode 100644 index 0000000..a93ea39 --- /dev/null +++ b/bsd-user/riscv/target_arch_cpu.h @@ -0,0 +1,148 @@ +/* + * RISC-V CPU init and loop + * + * Copyright (c) 2019 Mark Corbin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef TARGET_ARCH_CPU_H +#define TARGET_ARCH_CPU_H + +#include "target_arch.h" +#include "signal-common.h" + +#define TARGET_DEFAULT_CPU_MODEL "max" + +static inline void target_cpu_init(CPURISCVState *env, + struct target_pt_regs *regs) +{ + int i; + + for (i = 1; i < 32; i++) { + env->gpr[i] = regs->regs[i]; + } + + env->pc = regs->sepc; +} + +static inline void target_cpu_loop(CPURISCVState *env) +{ + CPUState *cs = env_cpu(env); + int trapnr; + abi_long ret; + unsigned int syscall_num; + int32_t signo, code; + + for (;;) { + cpu_exec_start(cs); + trapnr = cpu_exec(cs); + cpu_exec_end(cs); + process_queued_cpu_work(cs); + + signo = 0; + + switch (trapnr) { + case EXCP_INTERRUPT: + /* just indicate that signals should be handled asap */ + break; + case EXCP_ATOMIC: + cpu_exec_step_atomic(cs); + break; + case RISCV_EXCP_U_ECALL: + syscall_num = env->gpr[xT0]; + env->pc += TARGET_INSN_SIZE; + /* Compare to cpu_fetch_syscall_args() in riscv/riscv/trap.c */ + if (TARGET_FREEBSD_NR___syscall == syscall_num || + TARGET_FREEBSD_NR_syscall == syscall_num) { + ret = do_freebsd_syscall(env, + env->gpr[xA0], + env->gpr[xA1], + env->gpr[xA2], + env->gpr[xA3], + env->gpr[xA4], + env->gpr[xA5], + env->gpr[xA6], + env->gpr[xA7], + 0); + } else { + ret = do_freebsd_syscall(env, + syscall_num, + env->gpr[xA0], + env->gpr[xA1], + env->gpr[xA2], + env->gpr[xA3], + env->gpr[xA4], + env->gpr[xA5], + env->gpr[xA6], + env->gpr[xA7] + ); + } + + /* + * Compare to cpu_set_syscall_retval() in + * riscv/riscv/vm_machdep.c + */ + if (ret >= 0) { + env->gpr[xA0] = ret; + env->gpr[xT0] = 0; + } else if (ret == -TARGET_ERESTART) { + env->pc -= TARGET_INSN_SIZE; + } else if (ret != -TARGET_EJUSTRETURN) { + env->gpr[xA0] = -ret; + env->gpr[xT0] = 1; + } + break; + case RISCV_EXCP_ILLEGAL_INST: + signo = TARGET_SIGILL; + code = TARGET_ILL_ILLOPC; + break; + case RISCV_EXCP_BREAKPOINT: + signo = TARGET_SIGTRAP; + code = TARGET_TRAP_BRKPT; + break; + case EXCP_DEBUG: + signo = TARGET_SIGTRAP; + code = TARGET_TRAP_BRKPT; + break; + default: + fprintf(stderr, "qemu: unhandled CPU exception " + "0x%x - aborting\n", trapnr); + cpu_dump_state(cs, stderr, 0); + abort(); + } + + if (signo) { + force_sig_fault(signo, code, env->pc); + } + + process_pending_signals(env); + } +} + +static inline void target_cpu_clone_regs(CPURISCVState *env, target_ulong newsp) +{ + if (newsp) { + env->gpr[xSP] = newsp; + } + + env->gpr[xA0] = 0; + env->gpr[xT0] = 0; +} + +static inline void target_cpu_reset(CPUArchState *env) +{ +} + +#endif /* TARGET_ARCH_CPU_H */ diff --git a/bsd-user/riscv/target_arch_elf.h b/bsd-user/riscv/target_arch_elf.h new file mode 100644 index 0000000..4eb915e --- /dev/null +++ b/bsd-user/riscv/target_arch_elf.h @@ -0,0 +1,42 @@ +/* + * RISC-V ELF definitions + * + * Copyright (c) 2019 Mark Corbin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef TARGET_ARCH_ELF_H +#define TARGET_ARCH_ELF_H + +#define elf_check_arch(x) ((x) == EM_RISCV) +#define ELF_START_MMAP 0x80000000 +#define ELF_ET_DYN_LOAD_ADDR 0x100000 +#define ELF_CLASS ELFCLASS64 + +#define ELF_DATA ELFDATA2LSB +#define ELF_ARCH EM_RISCV + +#define ELF_HWCAP get_elf_hwcap() +static uint32_t get_elf_hwcap(void) +{ + RISCVCPU *cpu = RISCV_CPU(thread_cpu); + + return cpu->env.misa_ext_mask; +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +#endif /* TARGET_ARCH_ELF_H */ diff --git a/bsd-user/riscv/target_arch_reg.h b/bsd-user/riscv/target_arch_reg.h new file mode 100644 index 0000000..12b1c96 --- /dev/null +++ b/bsd-user/riscv/target_arch_reg.h @@ -0,0 +1,88 @@ +/* + * RISC-V register structures + * + * Copyright (c) 2019 Mark Corbin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef TARGET_ARCH_REG_H +#define TARGET_ARCH_REG_H + +/* Compare with riscv/include/reg.h */ +typedef struct target_reg { + uint64_t ra; /* return address */ + uint64_t sp; /* stack pointer */ + uint64_t gp; /* global pointer */ + uint64_t tp; /* thread pointer */ + uint64_t t[7]; /* temporaries */ + uint64_t s[12]; /* saved registers */ + uint64_t a[8]; /* function arguments */ + uint64_t sepc; /* exception program counter */ + uint64_t sstatus; /* status register */ +} target_reg_t; + +typedef struct target_fpreg { + uint64_t fp_x[32][2]; /* Floating point registers */ + uint64_t fp_fcsr; /* Floating point control reg */ +} target_fpreg_t; + +#define tswapreg(ptr) tswapal(ptr) + +/* Compare with struct trapframe in riscv/include/frame.h */ +static inline void target_copy_regs(target_reg_t *regs, + const CPURISCVState *env) +{ + + regs->ra = tswapreg(env->gpr[1]); + regs->sp = tswapreg(env->gpr[2]); + regs->gp = tswapreg(env->gpr[3]); + regs->tp = tswapreg(env->gpr[4]); + + regs->t[0] = tswapreg(env->gpr[5]); + regs->t[1] = tswapreg(env->gpr[6]); + regs->t[2] = tswapreg(env->gpr[7]); + regs->t[3] = tswapreg(env->gpr[28]); + regs->t[4] = tswapreg(env->gpr[29]); + regs->t[5] = tswapreg(env->gpr[30]); + regs->t[6] = tswapreg(env->gpr[31]); + + regs->s[0] = tswapreg(env->gpr[8]); + regs->s[1] = tswapreg(env->gpr[9]); + regs->s[2] = tswapreg(env->gpr[18]); + regs->s[3] = tswapreg(env->gpr[19]); + regs->s[4] = tswapreg(env->gpr[20]); + regs->s[5] = tswapreg(env->gpr[21]); + regs->s[6] = tswapreg(env->gpr[22]); + regs->s[7] = tswapreg(env->gpr[23]); + regs->s[8] = tswapreg(env->gpr[24]); + regs->s[9] = tswapreg(env->gpr[25]); + regs->s[10] = tswapreg(env->gpr[26]); + regs->s[11] = tswapreg(env->gpr[27]); + + regs->a[0] = tswapreg(env->gpr[10]); + regs->a[1] = tswapreg(env->gpr[11]); + regs->a[2] = tswapreg(env->gpr[12]); + regs->a[3] = tswapreg(env->gpr[13]); + regs->a[4] = tswapreg(env->gpr[14]); + regs->a[5] = tswapreg(env->gpr[15]); + regs->a[6] = tswapreg(env->gpr[16]); + regs->a[7] = tswapreg(env->gpr[17]); + + regs->sepc = tswapreg(env->pc); +} + +#undef tswapreg + +#endif /* TARGET_ARCH_REG_H */ diff --git a/bsd-user/riscv/target_arch_signal.h b/bsd-user/riscv/target_arch_signal.h new file mode 100644 index 0000000..1a634b8 --- /dev/null +++ b/bsd-user/riscv/target_arch_signal.h @@ -0,0 +1,75 @@ +/* + * RISC-V signal definitions + * + * Copyright (c) 2019 Mark Corbin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef TARGET_ARCH_SIGNAL_H +#define TARGET_ARCH_SIGNAL_H + +#include "cpu.h" + + +#define TARGET_INSN_SIZE 4 /* riscv instruction size */ + +/* Size of the signal trampoline code placed on the stack. */ +#define TARGET_SZSIGCODE ((abi_ulong)(7 * TARGET_INSN_SIZE)) + +/* Compare with riscv/include/_limits.h */ +#define TARGET_MINSIGSTKSZ (1024 * 4) +#define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768) + +struct target_gpregs { + uint64_t gp_ra; + uint64_t gp_sp; + uint64_t gp_gp; + uint64_t gp_tp; + uint64_t gp_t[7]; + uint64_t gp_s[12]; + uint64_t gp_a[8]; + uint64_t gp_sepc; + uint64_t gp_sstatus; +}; + +struct target_fpregs { + uint64_t fp_x[32][2]; + uint64_t fp_fcsr; + uint32_t fp_flags; + uint32_t pad; +}; + +typedef struct target_mcontext { + struct target_gpregs mc_gpregs; + struct target_fpregs mc_fpregs; + uint32_t mc_flags; +#define TARGET_MC_FP_VALID 0x01 + uint32_t mc_pad; + uint64_t mc_spare[8]; +} target_mcontext_t; + +#define TARGET_MCONTEXT_SIZE 864 +#define TARGET_UCONTEXT_SIZE 936 + +#include "target_os_ucontext.h" + +struct target_sigframe { + target_ucontext_t sf_uc; /* = *sf_uncontext */ + target_siginfo_t sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/ +}; + +#define TARGET_SIGSTACK_ALIGN 16 + +#endif /* TARGET_ARCH_SIGNAL_H */ diff --git a/bsd-user/riscv/target_arch_sigtramp.h b/bsd-user/riscv/target_arch_sigtramp.h new file mode 100644 index 0000000..dfe5076 --- /dev/null +++ b/bsd-user/riscv/target_arch_sigtramp.h @@ -0,0 +1,41 @@ +/* + * RISC-V sigcode + * + * Copyright (c) 2019 Mark Corbin + * + * 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_SIGTRAMP_H +#define TARGET_ARCH_SIGTRAMP_H + +/* Compare with sigcode() in riscv/riscv/locore.S */ +static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc, + unsigned sys_sigreturn) +{ + uint32_t sys_exit = TARGET_FREEBSD_NR_exit; + + uint32_t sigtramp_code[] = { + /*1*/ const_le32(0x00010513), /*mv a0, sp*/ + /*2*/ const_le32(0x00050513 + (sigf_uc << 20)), /*addi a0,a0,sigf_uc*/ + /*3*/ const_le32(0x00000293 + (sys_sigreturn << 20)),/*li t0,sys_sigreturn*/ + /*4*/ const_le32(0x00000073), /*ecall*/ + /*5*/ const_le32(0x00000293 + (sys_exit << 20)), /*li t0,sys_exit*/ + /*6*/ const_le32(0x00000073), /*ecall*/ + /*7*/ const_le32(0xFF1FF06F) /*b -16*/ + }; + + return memcpy_to_target(offset, sigtramp_code, TARGET_SZSIGCODE); +} +#endif /* TARGET_ARCH_SIGTRAMP_H */ diff --git a/bsd-user/riscv/target_arch_sysarch.h b/bsd-user/riscv/target_arch_sysarch.h new file mode 100644 index 0000000..9af4233 --- /dev/null +++ b/bsd-user/riscv/target_arch_sysarch.h @@ -0,0 +1,41 @@ +/* + * RISC-V sysarch() system call emulation + * + * Copyright (c) 2019 Mark Corbin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef TARGET_ARCH_SYSARCH_H +#define TARGET_ARCH_SYSARCH_H + +#include "target_syscall.h" +#include "target_arch.h" + +static inline abi_long do_freebsd_arch_sysarch(CPURISCVState *env, int op, + abi_ulong parms) +{ + + return -TARGET_EOPNOTSUPP; +} + +static inline void do_freebsd_arch_print_sysarch( + const struct syscallname *name, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6) +{ + + gemu_log("UNKNOWN OP: %d, " TARGET_ABI_FMT_lx ")", (int)arg1, arg2); +} + +#endif /* TARGET_ARCH_SYSARCH_H */ diff --git a/bsd-user/riscv/target_arch_thread.h b/bsd-user/riscv/target_arch_thread.h new file mode 100644 index 0000000..95cd0b6 --- /dev/null +++ b/bsd-user/riscv/target_arch_thread.h @@ -0,0 +1,47 @@ +/* + * RISC-V thread support + * + * Copyright (c) 2019 Mark Corbin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef TARGET_ARCH_THREAD_H +#define TARGET_ARCH_THREAD_H + +/* Compare with cpu_set_upcall() in riscv/riscv/vm_machdep.c */ +static inline void target_thread_set_upcall(CPURISCVState *regs, + abi_ulong entry, abi_ulong arg, abi_ulong stack_base, + abi_ulong stack_size) +{ + abi_ulong sp; + + sp = ROUND_DOWN(stack_base + stack_size, 16); + + regs->gpr[xSP] = sp; + regs->pc = entry; + regs->gpr[xA0] = arg; +} + +/* Compare with exec_setregs() in riscv/riscv/machdep.c */ +static inline void target_thread_init(struct target_pt_regs *regs, + struct image_info *infop) +{ + regs->sepc = infop->entry; + regs->regs[xRA] = infop->entry; + regs->regs[xA0] = infop->start_stack; + regs->regs[xSP] = ROUND_DOWN(infop->start_stack, 16); +} + +#endif /* TARGET_ARCH_THREAD_H */ diff --git a/bsd-user/riscv/target_arch_vmparam.h b/bsd-user/riscv/target_arch_vmparam.h new file mode 100644 index 0000000..0f2486d --- /dev/null +++ b/bsd-user/riscv/target_arch_vmparam.h @@ -0,0 +1,53 @@ +/* + * RISC-V VM parameters definitions + * + * Copyright (c) 2019 Mark Corbin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef TARGET_ARCH_VMPARAM_H +#define TARGET_ARCH_VMPARAM_H + +#include "cpu.h" + +/* Compare with riscv/include/vmparam.h */ +#define TARGET_MAXTSIZ (1 * GiB) /* max text size */ +#define TARGET_DFLDSIZ (128 * MiB) /* initial data size limit */ +#define TARGET_MAXDSIZ (1 * GiB) /* max data size */ +#define TARGET_DFLSSIZ (128 * MiB) /* initial stack size limit */ +#define TARGET_MAXSSIZ (1 * GiB) /* max stack size */ +#define TARGET_SGROWSIZ (128 * KiB) /* amount to grow stack */ + +#define TARGET_VM_MINUSER_ADDRESS (0x0000000000000000UL) +#define TARGET_VM_MAXUSER_ADDRESS (0x0000004000000000UL) + +#define TARGET_USRSTACK (TARGET_VM_MAXUSER_ADDRESS - TARGET_PAGE_SIZE) + +static inline abi_ulong get_sp_from_cpustate(CPURISCVState *state) +{ + return state->gpr[xSP]; +} + +static inline void set_second_rval(CPURISCVState *state, abi_ulong retval2) +{ + state->gpr[xA1] = retval2; +} + +static inline abi_ulong get_second_rval(CPURISCVState *state) +{ + return state->gpr[xA1]; +} + +#endif /* TARGET_ARCH_VMPARAM_H */ diff --git a/bsd-user/riscv/target_syscall.h b/bsd-user/riscv/target_syscall.h new file mode 100644 index 0000000..e7e5231 --- /dev/null +++ b/bsd-user/riscv/target_syscall.h @@ -0,0 +1,38 @@ +/* + * RISC-V system call definitions + * + * Copyright (c) Mark Corbin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef BSD_USER_RISCV_TARGET_SYSCALL_H +#define BSD_USER_RISCV_TARGET_SYSCALL_H + +/* + * struct target_pt_regs defines the way the registers are stored on the stack + * during a system call. + */ + +struct target_pt_regs { + abi_ulong regs[32]; + abi_ulong sepc; +}; + +#define UNAME_MACHINE "riscv64" + +#define TARGET_HW_MACHINE "riscv" +#define TARGET_HW_MACHINE_ARCH UNAME_MACHINE + +#endif /* BSD_USER_RISCV_TARGET_SYSCALL_H */ diff --git a/bsd-user/signal.c b/bsd-user/signal.c index 8b6654b..da49b9b 100644 --- a/bsd-user/signal.c +++ b/bsd-user/signal.c @@ -728,14 +728,7 @@ static inline abi_ulong get_sigframe(struct target_sigaction *ka, sp = ts->sigaltstack_used.ss_sp + ts->sigaltstack_used.ss_size; } -/* TODO: make this a target_arch function / define */ -#if defined(TARGET_ARM) - return (sp - frame_size) & ~7; -#elif defined(TARGET_AARCH64) - return (sp - frame_size) & ~15; -#else - return sp - frame_size; -#endif + return ROUND_DOWN(sp - frame_size, TARGET_SIGSTACK_ALIGN); } /* compare to $M/$M/exec_machdep.c sendsig and sys/kern/kern_sig.c sigexit */ diff --git a/bsd-user/x86_64/target_arch_signal.h b/bsd-user/x86_64/target_arch_signal.h index ca24bf1..f833ee6 100644 --- a/bsd-user/x86_64/target_arch_signal.h +++ b/bsd-user/x86_64/target_arch_signal.h @@ -97,4 +97,6 @@ struct target_sigframe { uint32_t __spare__[2]; }; +#define TARGET_SIGSTACK_ALIGN 16 + #endif /* TARGET_ARCH_SIGNAL_H */ |