Impleent COMPAT_FREEBSD32 for arm64.
This is based on early work by andrew@.
This commit is contained in:
parent
e42e878b35
commit
8c9c3144cc
@ -1,5 +1,14 @@
|
||||
/*-
|
||||
* Copyright (c) 2017 Nuxi, https://nuxi.nl/
|
||||
* Copyright (c) 2014, 2015 The FreeBSD Foundation.
|
||||
* Copyright (c) 2014, 2017 Andrew Turner.
|
||||
* Copyright (c) 2018 Olivier Houchard
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software was developed by Andrew Turner under
|
||||
* sponsorship from the FreeBSD Foundation.
|
||||
*
|
||||
* Portions of this software were developed by Konstantin Belousov
|
||||
* under sponsorship from the FreeBSD Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -26,13 +35,225 @@
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/types.h>
|
||||
#define __ELF_WORD_SIZE 32
|
||||
#define __ELF_WORD_SIZE 32
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/exec.h>
|
||||
#include <sys/imgact.h>
|
||||
#include <sys/linker.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/sysent.h>
|
||||
#include <sys/imgact_elf.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/signalvar.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <machine/elf.h>
|
||||
|
||||
#include <compat/freebsd32/freebsd32_util.h>
|
||||
|
||||
#define FREEBSD32_MINUSER 0x00001000
|
||||
#define FREEBSD32_MAXUSER ((1ul << 32) - PAGE_SIZE)
|
||||
#define FREEBSD32_SHAREDPAGE (FREEBSD32_MAXUSER - PAGE_SIZE)
|
||||
#define FREEBSD32_USRSTACK FREEBSD32_SHAREDPAGE
|
||||
|
||||
extern const char *freebsd32_syscallnames[];
|
||||
|
||||
extern char aarch32_sigcode[];
|
||||
extern int sz_aarch32_sigcode;
|
||||
|
||||
static int freebsd32_fetch_syscall_args(struct thread *td);
|
||||
static void freebsd32_setregs(struct thread *td, struct image_params *imgp,
|
||||
u_long stack);
|
||||
static void freebsd32_set_syscall_retval(struct thread *, int);
|
||||
|
||||
static boolean_t elf32_arm_abi_supported(struct image_params *);
|
||||
|
||||
extern void freebsd32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask);
|
||||
|
||||
static struct sysentvec elf32_freebsd_sysvec = {
|
||||
.sv_size = SYS_MAXSYSCALL,
|
||||
.sv_table = freebsd32_sysent,
|
||||
.sv_errsize = 0,
|
||||
.sv_errtbl = NULL,
|
||||
.sv_transtrap = NULL,
|
||||
.sv_fixup = elf32_freebsd_fixup,
|
||||
.sv_sendsig = freebsd32_sendsig,
|
||||
.sv_sigcode = aarch32_sigcode,
|
||||
.sv_szsigcode = &sz_aarch32_sigcode,
|
||||
.sv_name = "FreeBSD ELF32",
|
||||
.sv_coredump = elf32_coredump,
|
||||
.sv_imgact_try = NULL,
|
||||
.sv_minsigstksz = MINSIGSTKSZ,
|
||||
.sv_pagesize = PAGE_SIZE,
|
||||
.sv_minuser = FREEBSD32_MINUSER,
|
||||
.sv_maxuser = FREEBSD32_MAXUSER,
|
||||
.sv_usrstack = FREEBSD32_USRSTACK,
|
||||
.sv_psstrings = FREEBSD32_PS_STRINGS,
|
||||
.sv_stackprot = VM_PROT_READ | VM_PROT_WRITE,
|
||||
.sv_copyout_strings = freebsd32_copyout_strings,
|
||||
.sv_setregs = freebsd32_setregs,
|
||||
.sv_fixlimit = NULL, // XXX
|
||||
.sv_maxssiz = NULL,
|
||||
.sv_flags = SV_ABI_FREEBSD | SV_ILP32 | SV_SHP | SV_TIMEKEEP,
|
||||
.sv_set_syscall_retval = freebsd32_set_syscall_retval,
|
||||
.sv_fetch_syscall_args = freebsd32_fetch_syscall_args,
|
||||
.sv_syscallnames = freebsd32_syscallnames,
|
||||
.sv_shared_page_base = FREEBSD32_SHAREDPAGE,
|
||||
.sv_shared_page_len = PAGE_SIZE,
|
||||
.sv_schedtail = NULL,
|
||||
.sv_thread_detach = NULL,
|
||||
.sv_trap = NULL,
|
||||
};
|
||||
INIT_SYSENTVEC(elf32_sysvec, &elf32_freebsd_sysvec);
|
||||
|
||||
static Elf32_Brandinfo freebsd32_brand_info = {
|
||||
.brand = ELFOSABI_FREEBSD,
|
||||
.machine = EM_ARM,
|
||||
.compat_3_brand = "FreeBSD",
|
||||
.emul_path = NULL,
|
||||
.interp_path = "/libexec/ld-elf.so.1",
|
||||
.sysvec = &elf32_freebsd_sysvec,
|
||||
.interp_newpath = NULL,
|
||||
.brand_note = &elf32_freebsd_brandnote,
|
||||
.flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE,
|
||||
.header_supported= elf32_arm_abi_supported,
|
||||
};
|
||||
|
||||
SYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_FIRST,
|
||||
(sysinit_cfunc_t)elf32_insert_brand_entry, &freebsd32_brand_info);
|
||||
|
||||
static boolean_t
|
||||
elf32_arm_abi_supported(struct image_params *imgp)
|
||||
{
|
||||
const Elf32_Ehdr *hdr;
|
||||
|
||||
/* Check if we support AArch32 */
|
||||
if (ID_AA64PFR0_EL0(READ_SPECIALREG(id_aa64pfr0_el1)) !=
|
||||
ID_AA64PFR0_EL0_64_32)
|
||||
return (FALSE);
|
||||
|
||||
#define EF_ARM_EABI_VERSION(x) (((x) & EF_ARM_EABIMASK) >> 24)
|
||||
#define EF_ARM_EABI_FREEBSD_MIN 4
|
||||
hdr = (const Elf32_Ehdr *)imgp->image_header;
|
||||
if (EF_ARM_EABI_VERSION(hdr->e_flags) < EF_ARM_EABI_FREEBSD_MIN) {
|
||||
if (bootverbose)
|
||||
uprintf("Attempting to execute non EABI binary "
|
||||
"(rev %d) image %s",
|
||||
EF_ARM_EABI_VERSION(hdr->e_flags),
|
||||
imgp->args->fname);
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
static int
|
||||
freebsd32_fetch_syscall_args(struct thread *td)
|
||||
{
|
||||
struct proc *p;
|
||||
register_t *ap;
|
||||
struct syscall_args *sa;
|
||||
int error, i, nap;
|
||||
unsigned int args[4];
|
||||
|
||||
nap = 4;
|
||||
p = td->td_proc;
|
||||
ap = td->td_frame->tf_x;
|
||||
sa = &td->td_sa;
|
||||
|
||||
/* r7 is the syscall id */
|
||||
sa->code = td->td_frame->tf_x[7];
|
||||
|
||||
if (sa->code == SYS_syscall) {
|
||||
sa->code = *ap++;
|
||||
nap--;
|
||||
} else if (sa->code == SYS___syscall) {
|
||||
sa->code = ap[1];
|
||||
nap -= 2;
|
||||
ap += 2;
|
||||
}
|
||||
|
||||
if (sa->code >= p->p_sysent->sv_size)
|
||||
sa->callp = &p->p_sysent->sv_table[0];
|
||||
else
|
||||
sa->callp = &p->p_sysent->sv_table[sa->code];
|
||||
|
||||
sa->narg = sa->callp->sy_narg;
|
||||
for (i = 0; i < nap; i++)
|
||||
sa->args[i] = ap[i];
|
||||
if (sa->narg > nap) {
|
||||
if ((sa->narg - nap) > nitems(args))
|
||||
panic("Too many system call arguiments");
|
||||
error = copyin((void *)td->td_frame->tf_x[13], args,
|
||||
(sa->narg - nap) * sizeof(int));
|
||||
for (i = 0; i < (sa->narg - nap); i++)
|
||||
sa->args[i + nap] = args[i];
|
||||
}
|
||||
|
||||
td->td_retval[0] = 0;
|
||||
td->td_retval[1] = 0;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
freebsd32_set_syscall_retval(struct thread *td, int error)
|
||||
{
|
||||
struct trapframe *frame;
|
||||
|
||||
frame = td->td_frame;
|
||||
switch (error) {
|
||||
case 0:
|
||||
frame->tf_x[0] = td->td_retval[0];
|
||||
frame->tf_x[1] = td->td_retval[1];
|
||||
frame->tf_spsr &= ~PSR_C;
|
||||
break;
|
||||
case ERESTART:
|
||||
/*
|
||||
* Reconstruct the pc to point at the swi.
|
||||
*/
|
||||
if ((frame->tf_spsr & PSR_T) != 0)
|
||||
frame->tf_elr -= 2; //THUMB_INSN_SIZE;
|
||||
else
|
||||
frame->tf_elr -= 4; //INSN_SIZE;
|
||||
break;
|
||||
case EJUSTRETURN:
|
||||
/* nothing to do */
|
||||
break;
|
||||
default:
|
||||
frame->tf_x[0] = error;
|
||||
frame->tf_spsr |= PSR_C;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
freebsd32_setregs(struct thread *td, struct image_params *imgp,
|
||||
u_long stack)
|
||||
{
|
||||
struct trapframe *tf = td->td_frame;
|
||||
|
||||
memset(tf, 0, sizeof(struct trapframe));
|
||||
|
||||
/*
|
||||
* We need to set x0 for init as it doesn't call
|
||||
* cpu_set_syscall_retval to copy the value. We also
|
||||
* need to set td_retval for the cases where we do.
|
||||
*/
|
||||
tf->tf_x[0] = stack;
|
||||
/* SP_usr is mapped to x13 */
|
||||
tf->tf_x[13] = stack;
|
||||
/* LR_usr is mapped to x14 */
|
||||
tf->tf_x[14] = imgp->entry_addr;
|
||||
tf->tf_elr = imgp->entry_addr;
|
||||
tf->tf_spsr = PSR_M_32;
|
||||
}
|
||||
|
||||
void
|
||||
elf32_dump_thread(struct thread *td __unused, void *dst __unused,
|
||||
size_t *off __unused)
|
||||
elf32_dump_thread(struct thread *td, void *dst, size_t *off)
|
||||
{
|
||||
|
||||
/* XXX: VFP */
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
/*-
|
||||
* Copyright (c) 2018 Olivier Houchard
|
||||
* Copyright (c) 2017 Nuxi, https://nuxi.nl/
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -27,44 +28,382 @@
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <sys/proc.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/syscallsubr.h>
|
||||
#include <sys/ktr.h>
|
||||
#include <sys/sysent.h>
|
||||
#include <machine/armreg.h>
|
||||
#ifdef VFP
|
||||
#include <machine/vfp.h>
|
||||
#endif
|
||||
#include <compat/freebsd32/freebsd32_proto.h>
|
||||
#include <compat/freebsd32/freebsd32_signal.h>
|
||||
|
||||
extern void freebsd32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask);
|
||||
|
||||
/*
|
||||
* The first two fields of a ucontext_t are the signal mask and the machine
|
||||
* context. The next field is uc_link; we want to avoid destroying the link
|
||||
* when copying out contexts.
|
||||
*/
|
||||
#define UC32_COPY_SIZE offsetof(ucontext32_t, uc_link)
|
||||
|
||||
#ifdef VFP
|
||||
static void get_fpcontext32(struct thread *td, mcontext32_vfp_t *);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Stubs for machine dependent 32-bits system calls.
|
||||
*/
|
||||
|
||||
int
|
||||
freebsd32_sysarch(struct thread *td, struct freebsd32_sysarch_args *uap)
|
||||
{
|
||||
int error;
|
||||
|
||||
#define ARM_SYNC_ICACHE 0
|
||||
#define ARM_DRAIN_WRITEBUF 1
|
||||
#define ARM_SET_TP 2
|
||||
#define ARM_GET_TP 3
|
||||
#define ARM_GET_VFPSTATE 4
|
||||
|
||||
switch(uap->op) {
|
||||
case ARM_SET_TP:
|
||||
WRITE_SPECIALREG(TPIDR_EL0, uap->parms);
|
||||
WRITE_SPECIALREG(TPIDRRO_EL0, uap->parms);
|
||||
return 0;
|
||||
case ARM_SYNC_ICACHE:
|
||||
{
|
||||
struct {
|
||||
uint32_t addr;
|
||||
uint32_t size;
|
||||
} args;
|
||||
|
||||
if ((error = copyin(uap->parms, &args, sizeof(args))) != 0)
|
||||
return (error);
|
||||
if ((uint64_t)args.addr + (uint64_t)args.size > 0xffffffff)
|
||||
return (EINVAL);
|
||||
cpu_icache_sync_range(args.addr, args.size);
|
||||
return 0;
|
||||
}
|
||||
case ARM_GET_VFPSTATE:
|
||||
{
|
||||
mcontext32_vfp_t mcontext_vfp;
|
||||
|
||||
struct {
|
||||
uint32_t mc_vfp_size;
|
||||
uint32_t mc_vfp;
|
||||
} args;
|
||||
if ((error = copyin(uap->parms, &args, sizeof(args))) != 0)
|
||||
return (error);
|
||||
if (args.mc_vfp_size != sizeof(mcontext_vfp))
|
||||
return (EINVAL);
|
||||
#ifdef VFP
|
||||
get_fpcontext32(td, &mcontext_vfp);
|
||||
#else
|
||||
bzero(&mcontext_vfp, sizeof(mcontext_vfp));
|
||||
#endif
|
||||
error = copyout(&mcontext_vfp,
|
||||
(void *)(uintptr_t)args.mc_vfp,
|
||||
sizeof(mcontext_vfp));
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef VFP
|
||||
static void
|
||||
get_fpcontext32(struct thread *td, mcontext32_vfp_t *mcp)
|
||||
{
|
||||
struct pcb *curpcb;
|
||||
|
||||
critical_enter();
|
||||
curpcb = curthread->td_pcb;
|
||||
|
||||
if ((curpcb->pcb_fpflags & PCB_FP_STARTED) != 0) {
|
||||
/*
|
||||
* If we have just been running VFP instructions we will
|
||||
* need to save the state to memcpy it below.
|
||||
*/
|
||||
vfp_save_state(td, curpcb);
|
||||
|
||||
KASSERT(curpcb->pcb_fpusaved == &curpcb->pcb_fpustate,
|
||||
("Called get_fpcontext while the kernel is using the VFP"));
|
||||
KASSERT((curpcb->pcb_fpflags & ~PCB_FP_USERMASK) == 0,
|
||||
("Non-userspace FPU flags set in get_fpcontext"));
|
||||
memcpy(mcp->mcv_reg, curpcb->pcb_fpustate.vfp_regs,
|
||||
sizeof(mcp->mcv_reg));
|
||||
mcp->mcv_fpscr = VFP_FPSCR_FROM_SRCR(curpcb->pcb_fpustate.vfp_fpcr,
|
||||
curpcb->pcb_fpustate.vfp_fpsr);
|
||||
}
|
||||
critical_exit();
|
||||
}
|
||||
|
||||
static void
|
||||
set_fpcontext32(struct thread *td, mcontext32_vfp_t *mcp)
|
||||
{
|
||||
struct pcb *pcb;
|
||||
|
||||
critical_enter();
|
||||
pcb = td->td_pcb;
|
||||
if (td == curthread)
|
||||
vfp_discard(td);
|
||||
memcpy(pcb->pcb_fpustate.vfp_regs, mcp->mcv_reg,
|
||||
sizeof(pcb->pcb_fpustate.vfp_regs));
|
||||
pcb->pcb_fpustate.vfp_fpsr = VFP_FPSR_FROM_FPSCR(mcp->mcv_fpscr);
|
||||
pcb->pcb_fpustate.vfp_fpcr = VFP_FPSR_FROM_FPSCR(mcp->mcv_fpscr);
|
||||
critical_exit();
|
||||
}
|
||||
#endif
|
||||
static void
|
||||
get_mcontext32(struct thread *td, mcontext32_t *mcp, int flags)
|
||||
{
|
||||
struct pcb *pcb;
|
||||
struct trapframe *tf;
|
||||
int i;
|
||||
|
||||
pcb = td->td_pcb;
|
||||
tf = td->td_frame;
|
||||
|
||||
if ((flags & GET_MC_CLEAR_RET) != 0) {
|
||||
mcp->mc_gregset[0] = 0;
|
||||
mcp->mc_gregset[16] = tf->tf_spsr & ~PSR_C;
|
||||
} else {
|
||||
mcp->mc_gregset[0] = tf->tf_x[0];
|
||||
mcp->mc_gregset[16] = tf->tf_spsr;
|
||||
}
|
||||
for (i = 1; i < 15; i++)
|
||||
mcp->mc_gregset[i] = tf->tf_x[i];
|
||||
mcp->mc_gregset[15] = tf->tf_elr;
|
||||
|
||||
mcp->mc_vfp_size = 0;
|
||||
mcp->mc_vfp_ptr = 0;
|
||||
|
||||
memset(mcp->mc_spare, 0, sizeof(mcp->mc_spare));
|
||||
}
|
||||
|
||||
static int
|
||||
set_mcontext32(struct thread *td, mcontext32_t *mcp)
|
||||
{
|
||||
struct trapframe *tf;
|
||||
mcontext32_vfp_t mc_vfp;
|
||||
int i;
|
||||
|
||||
tf = td->td_frame;
|
||||
|
||||
for (i = 0; i < 15; i++)
|
||||
tf->tf_x[i] = mcp->mc_gregset[i];
|
||||
tf->tf_elr = mcp->mc_gregset[15];
|
||||
tf->tf_spsr = mcp->mc_gregset[16];
|
||||
#ifdef VFP
|
||||
if (mcp->mc_vfp_size == sizeof(mc_vfp) && mcp->mc_vfp_ptr != 0) {
|
||||
if (copyin((void *)(uintptr_t)mcp->mc_vfp_ptr, &mc_vfp,
|
||||
sizeof(mc_vfp)) != 0)
|
||||
return (EFAULT);
|
||||
set_fpcontext32(td, &mc_vfp);
|
||||
}
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
#define UC_COPY_SIZE offsetof(ucontext32_t, uc_link)
|
||||
|
||||
int
|
||||
freebsd32_getcontext(struct thread *td, struct freebsd32_getcontext_args *uap)
|
||||
{
|
||||
ucontext32_t uc;
|
||||
int ret;
|
||||
|
||||
return (ENOSYS);
|
||||
if (uap->ucp == NULL)
|
||||
ret = EINVAL;
|
||||
else {
|
||||
memset(&uc, 0, sizeof(uc));
|
||||
get_mcontext32(td, &uc.uc_mcontext, GET_MC_CLEAR_RET);
|
||||
PROC_LOCK(td->td_proc);
|
||||
uc.uc_sigmask = td->td_sigmask;
|
||||
PROC_UNLOCK(td->td_proc);
|
||||
ret = copyout(&uc, uap->ucp, UC_COPY_SIZE);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
freebsd32_setcontext(struct thread *td, struct freebsd32_setcontext_args *uap)
|
||||
{
|
||||
ucontext32_t uc;
|
||||
int ret;
|
||||
|
||||
return (ENOSYS);
|
||||
if (uap->ucp == NULL)
|
||||
ret = EINVAL;
|
||||
else {
|
||||
ret = copyin(uap->ucp, &uc, UC_COPY_SIZE);
|
||||
if (ret == 0) {
|
||||
ret = set_mcontext32(td, &uc.uc_mcontext);
|
||||
if (ret == 0)
|
||||
kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask,
|
||||
NULL, 0);
|
||||
}
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
freebsd32_sigreturn(struct thread *td, struct freebsd32_sigreturn_args *uap)
|
||||
{
|
||||
ucontext32_t uc;
|
||||
int error;
|
||||
|
||||
if (uap == NULL)
|
||||
return (EFAULT);
|
||||
if (copyin(uap->sigcntxp, &uc, sizeof(uc)))
|
||||
return (EFAULT);
|
||||
error = set_mcontext32(td, &uc.uc_mcontext);
|
||||
if (error != 0)
|
||||
return (0);
|
||||
|
||||
/* Restore signal mask. */
|
||||
kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0);
|
||||
|
||||
return (EJUSTRETURN);
|
||||
|
||||
return (ENOSYS);
|
||||
}
|
||||
|
||||
int
|
||||
freebsd32_swapcontext(struct thread *td, struct freebsd32_swapcontext_args *uap)
|
||||
{
|
||||
ucontext32_t uc;
|
||||
int ret;
|
||||
|
||||
return (ENOSYS);
|
||||
if (uap->oucp == NULL || uap->ucp == NULL)
|
||||
ret = EINVAL;
|
||||
else {
|
||||
get_mcontext32(td, &uc.uc_mcontext, GET_MC_CLEAR_RET);
|
||||
PROC_LOCK(td->td_proc);
|
||||
uc.uc_sigmask = td->td_sigmask;
|
||||
PROC_UNLOCK(td->td_proc);
|
||||
ret = copyout(&uc, uap->oucp, UC32_COPY_SIZE);
|
||||
if (ret == 0) {
|
||||
ret = copyin(uap->ucp, &uc, UC32_COPY_SIZE);
|
||||
if (ret == 0) {
|
||||
ret = set_mcontext32(td, &uc.uc_mcontext);
|
||||
kern_sigprocmask(td, SIG_SETMASK,
|
||||
&uc.uc_sigmask, NULL, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
freebsd32_sysarch(struct thread *td, struct freebsd32_sysarch_args *uap)
|
||||
void
|
||||
freebsd32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
|
||||
{
|
||||
struct thread *td;
|
||||
struct proc *p;
|
||||
struct trapframe *tf;
|
||||
struct sigframe32 *fp, frame;
|
||||
struct sigacts *psp;
|
||||
struct siginfo32 siginfo;
|
||||
struct sysentvec *sysent;
|
||||
int onstack;
|
||||
int sig;
|
||||
int code;
|
||||
|
||||
siginfo_to_siginfo32(&ksi->ksi_info, &siginfo);
|
||||
td = curthread;
|
||||
p = td->td_proc;
|
||||
PROC_LOCK_ASSERT(p, MA_OWNED);
|
||||
sig = ksi->ksi_signo;
|
||||
code = ksi->ksi_code;
|
||||
psp = p->p_sigacts;
|
||||
mtx_assert(&psp->ps_mtx, MA_OWNED);
|
||||
tf = td->td_frame;
|
||||
onstack = sigonstack(tf->tf_x[13]);
|
||||
|
||||
CTR4(KTR_SIG, "sendsig: td=%p (%s) catcher=%p sig=%d", td, p->p_comm,
|
||||
catcher, sig);
|
||||
|
||||
/* Allocate and validate space for the signal handler context. */
|
||||
if ((td->td_pflags & TDP_ALTSTACK) != 0 && !(onstack) &&
|
||||
SIGISMEMBER(psp->ps_sigonstack, sig)) {
|
||||
fp = (struct sigframe32 *)((uintptr_t)td->td_sigstk.ss_sp +
|
||||
td->td_sigstk.ss_size);
|
||||
#if defined(COMPAT_43)
|
||||
td->td_sigstk.ss_flags |= SS_ONSTACK;
|
||||
#endif
|
||||
} else
|
||||
fp = (struct sigframe32 *)td->td_frame->tf_x[13];
|
||||
|
||||
/* make room on the stack */
|
||||
fp--;
|
||||
|
||||
/* make the stack aligned */
|
||||
fp = (struct sigframe32 *)((unsigned long)(fp) &~ (8 - 1));
|
||||
/* Populate the siginfo frame. */
|
||||
get_mcontext32(td, &frame.sf_uc.uc_mcontext, 0);
|
||||
#ifdef VFP
|
||||
get_fpcontext32(td, &frame.sf_vfp);
|
||||
frame.sf_uc.uc_mcontext.mc_vfp_size = sizeof(fp->sf_vfp);
|
||||
frame.sf_uc.uc_mcontext.mc_vfp_ptr = (uint32_t)(uintptr_t)&fp->sf_vfp;
|
||||
#else
|
||||
frame.sf_uc.uc_mcontext.mc_vfp_size = 0;
|
||||
frame.sf_uc.uc_mcontext.mc_vfp_ptr = (uint32_t)NULL;
|
||||
#endif
|
||||
frame.sf_si = siginfo;
|
||||
frame.sf_uc.uc_sigmask = *mask;
|
||||
frame.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK )
|
||||
? ((onstack) ? SS_ONSTACK : 0) : SS_DISABLE;
|
||||
frame.sf_uc.uc_stack.ss_sp = (uintptr_t)td->td_sigstk.ss_sp;
|
||||
frame.sf_uc.uc_stack.ss_size = td->td_sigstk.ss_size;
|
||||
|
||||
mtx_unlock(&psp->ps_mtx);
|
||||
PROC_UNLOCK(td->td_proc);
|
||||
|
||||
/* Copy the sigframe out to the user's stack. */
|
||||
if (copyout(&frame, fp, sizeof(*fp)) != 0) {
|
||||
/* Process has trashed its stack. Kill it. */
|
||||
CTR2(KTR_SIG, "sendsig: sigexit td=%p fp=%p", td, fp);
|
||||
PROC_LOCK(p);
|
||||
sigexit(td, SIGILL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Build context to run handler in. We invoke the handler
|
||||
* directly, only returning via the trampoline. Note the
|
||||
* trampoline version numbers are coordinated with machine-
|
||||
* dependent code in libc.
|
||||
*/
|
||||
|
||||
tf->tf_x[0] = sig;
|
||||
tf->tf_x[1] = (register_t)&fp->sf_si;
|
||||
tf->tf_x[2] = (register_t)&fp->sf_uc;
|
||||
|
||||
/* the trampoline uses r5 as the uc address */
|
||||
tf->tf_x[5] = (register_t)&fp->sf_uc;
|
||||
tf->tf_elr = (register_t)catcher;
|
||||
tf->tf_x[13] = (register_t)fp;
|
||||
sysent = p->p_sysent;
|
||||
if (sysent->sv_sigcode_base != 0)
|
||||
tf->tf_x[14] = (register_t)sysent->sv_sigcode_base;
|
||||
else
|
||||
tf->tf_x[14] = (register_t)(sysent->sv_psstrings -
|
||||
*(sysent->sv_szsigcode));
|
||||
/* Set the mode to enter in the signal handler */
|
||||
if ((register_t)catcher & 1)
|
||||
tf->tf_spsr |= PSR_T;
|
||||
else
|
||||
tf->tf_spsr &= ~PSR_T;
|
||||
|
||||
CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_x[14],
|
||||
tf->tf_x[13]);
|
||||
|
||||
PROC_LOCK(p);
|
||||
mtx_lock(&psp->ps_mtx);
|
||||
|
||||
return (ENOSYS);
|
||||
}
|
||||
|
@ -49,8 +49,28 @@ static int ident_lock;
|
||||
|
||||
char machine[] = "arm64";
|
||||
|
||||
SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0,
|
||||
"Machine class");
|
||||
#ifdef SCTL_MASK32
|
||||
extern int adaptive_machine_arch;
|
||||
#endif
|
||||
|
||||
static int
|
||||
sysctl_hw_machine(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
#ifdef SCTL_MASK32
|
||||
static const char machine32[] = "arm";
|
||||
#endif
|
||||
int error;
|
||||
#ifdef SCTL_MASK32
|
||||
if ((req->flags & SCTL_MASK32) != 0 && adaptive_machine_arch)
|
||||
error = SYSCTL_OUT(req, machine32, sizeof(machine32));
|
||||
else
|
||||
#endif
|
||||
error = SYSCTL_OUT(req, machine, sizeof(machine));
|
||||
return (error);
|
||||
}
|
||||
|
||||
SYSCTL_PROC(_hw, HW_MACHINE, machine, CTLTYPE_STRING | CTLFLAG_RD |
|
||||
CTLFLAG_MPSAFE, NULL, 0, sysctl_hw_machine, "A", "Machine class");
|
||||
|
||||
/*
|
||||
* Per-CPU affinity as provided in MPIDR_EL1
|
||||
|
@ -699,3 +699,21 @@ esigcode:
|
||||
.global szsigcode
|
||||
szsigcode:
|
||||
.quad esigcode - sigcode
|
||||
|
||||
ENTRY(aarch32_sigcode)
|
||||
.word 0xe1a0000d // mov r0, sp
|
||||
.word 0xe2800040 // add r0, r0, #SIGF_UC
|
||||
.word 0xe59f700c // ldr r7, [pc, #12]
|
||||
.word 0xef000000 // swi #0
|
||||
.word 0xe59f7008 // ldr r7, [pc, #8]
|
||||
.word 0xef000000 // swi #0
|
||||
.word 0xeafffffa // b . - 16
|
||||
END(aarch32_sigcode)
|
||||
.word SYS_sigreturn
|
||||
.word SYS_exit
|
||||
.align 3
|
||||
aarch32_esigcode:
|
||||
.data
|
||||
.global sz_aarch32_sigcode
|
||||
sz_aarch32_sigcode:
|
||||
.quad aarch32_esigcode - aarch32_sigcode
|
||||
|
@ -276,17 +276,36 @@ set_dbregs(struct thread *td, struct dbreg *regs)
|
||||
int
|
||||
fill_regs32(struct thread *td, struct reg32 *regs)
|
||||
{
|
||||
int i;
|
||||
struct trapframe *tf;
|
||||
|
||||
printf("ARM64TODO: fill_regs32");
|
||||
return (EDOOFUS);
|
||||
tf = td->td_frame;
|
||||
for (i = 0; i < 13; i++)
|
||||
regs->r[i] = tf->tf_x[i];
|
||||
regs->r_sp = tf->tf_sp;
|
||||
regs->r_lr = tf->tf_lr;
|
||||
regs->r_pc = tf->tf_elr;
|
||||
regs->r_cpsr = tf->tf_spsr;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
set_regs32(struct thread *td, struct reg32 *regs)
|
||||
{
|
||||
int i;
|
||||
struct trapframe *tf;
|
||||
|
||||
printf("ARM64TODO: set_regs32");
|
||||
return (EDOOFUS);
|
||||
tf = td->td_frame;
|
||||
for (i = 0; i < 13; i++)
|
||||
tf->tf_x[i] = regs->r[i];
|
||||
tf->tf_sp = regs->r_sp;
|
||||
tf->tf_lr = regs->r_lr;
|
||||
tf->tf_elr = regs->r_pc;
|
||||
tf->tf_spsr = regs->r_cpsr;
|
||||
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -35,10 +35,15 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/signal.h>
|
||||
#include <sys/signalvar.h>
|
||||
#include <sys/sysent.h>
|
||||
|
||||
#include <machine/frame.h>
|
||||
#include <machine/undefined.h>
|
||||
#include <machine/vmparam.h>
|
||||
|
||||
MALLOC_DEFINE(M_UNDEF, "undefhandler", "Undefined instruction handler data");
|
||||
|
||||
@ -83,6 +88,33 @@ id_aa64mmfr2_handler(vm_offset_t va, uint32_t insn, struct trapframe *frame,
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifdef COMPAT_FREEBSD32
|
||||
/* arm32 GDB breakpoints */
|
||||
#define GDB_BREAKPOINT 0xe6000011
|
||||
#define GDB5_BREAKPOINT 0xe7ffdefe
|
||||
static int
|
||||
gdb_trapper(vm_offset_t va, uint32_t insn, struct trapframe *frame,
|
||||
uint32_t esr)
|
||||
{
|
||||
struct thread *td = curthread;
|
||||
|
||||
if (insn == GDB_BREAKPOINT || insn == GDB5_BREAKPOINT) {
|
||||
if (SV_PROC_FLAG(td->td_proc, SV_ILP32) &&
|
||||
va < VM_MAXUSER_ADDRESS) {
|
||||
ksiginfo_t ksi;
|
||||
|
||||
ksiginfo_init_trap(&ksi);
|
||||
ksi.ksi_signo = SIGTRAP;
|
||||
ksi.ksi_code = TRAP_TRACE;
|
||||
ksi.ksi_addr = (void *)va;
|
||||
trapsignal(td, &ksi);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
undef_init(void)
|
||||
{
|
||||
@ -91,6 +123,9 @@ undef_init(void)
|
||||
LIST_INIT(&undef_handlers[1]);
|
||||
|
||||
install_undef_handler(false, id_aa64mmfr2_handler);
|
||||
#ifdef COMPAT_FREEBSD32
|
||||
install_undef_handler(true, gdb_trapper);
|
||||
#endif
|
||||
}
|
||||
|
||||
void *
|
||||
|
@ -78,6 +78,7 @@ cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags)
|
||||
* this may not have happened.
|
||||
*/
|
||||
td1->td_pcb->pcb_tpidr_el0 = READ_SPECIALREG(tpidr_el0);
|
||||
td1->td_pcb->pcb_tpidrro_el0 = READ_SPECIALREG(tpidrro_el0);
|
||||
#ifdef VFP
|
||||
if ((td1->td_pcb->pcb_fpflags & PCB_FP_STARTED) != 0)
|
||||
vfp_save_state(td1, td1->td_pcb);
|
||||
@ -97,7 +98,7 @@ cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags)
|
||||
bcopy(td1->td_frame, tf, sizeof(*tf));
|
||||
tf->tf_x[0] = 0;
|
||||
tf->tf_x[1] = 0;
|
||||
tf->tf_spsr = 0;
|
||||
tf->tf_spsr = td1->td_frame->tf_spsr & PSR_M_32;
|
||||
|
||||
td2->td_frame = tf;
|
||||
|
||||
@ -195,7 +196,11 @@ cpu_set_upcall(struct thread *td, void (*entry)(void *), void *arg,
|
||||
{
|
||||
struct trapframe *tf = td->td_frame;
|
||||
|
||||
tf->tf_sp = STACKALIGN((uintptr_t)stack->ss_sp + stack->ss_size);
|
||||
/* 32bits processes use r13 for sp */
|
||||
if (td->td_frame->tf_spsr & PSR_M_32)
|
||||
tf->tf_x[13] = STACKALIGN((uintptr_t)stack->ss_sp + stack->ss_size);
|
||||
else
|
||||
tf->tf_sp = STACKALIGN((uintptr_t)stack->ss_sp + stack->ss_size);
|
||||
tf->tf_elr = (register_t)entry;
|
||||
tf->tf_x[0] = (register_t)arg;
|
||||
}
|
||||
@ -209,9 +214,19 @@ cpu_set_user_tls(struct thread *td, void *tls_base)
|
||||
return (EINVAL);
|
||||
|
||||
pcb = td->td_pcb;
|
||||
pcb->pcb_tpidr_el0 = (register_t)tls_base;
|
||||
if (td == curthread)
|
||||
WRITE_SPECIALREG(tpidr_el0, tls_base);
|
||||
if (td->td_frame->tf_spsr & PSR_M_32) {
|
||||
/* 32bits arm stores the user TLS into tpidrro */
|
||||
pcb->pcb_tpidrro_el0 = (register_t)tls_base;
|
||||
pcb->pcb_tpidr_el0 = (register_t)tls_base;
|
||||
if (td == curthread) {
|
||||
WRITE_SPECIALREG(tpidrro_el0, tls_base);
|
||||
WRITE_SPECIALREG(tpidr_el0, tls_base);
|
||||
}
|
||||
} else {
|
||||
pcb->pcb_tpidr_el0 = (register_t)tls_base;
|
||||
if (td == curthread)
|
||||
WRITE_SPECIALREG(tpidr_el0, tls_base);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ options PROCFS # Process filesystem (requires PSEUDOFS)
|
||||
options PSEUDOFS # Pseudo-filesystem framework
|
||||
options GEOM_RAID # Soft RAID functionality.
|
||||
options GEOM_LABEL # Provides labelization
|
||||
options COMPAT_FREEBSD32 # Incomplete, but used by cloudabi32.ko.
|
||||
options COMPAT_FREEBSD32 # Compatible with FreeBSD/arm
|
||||
options COMPAT_FREEBSD11 # Compatible with FreeBSD11
|
||||
options SCSI_DELAY=5000 # Delay (in ms) before probing SCSI
|
||||
options KTRACE # ktrace(1) support
|
||||
|
@ -575,8 +575,12 @@
|
||||
#define PSR_M_EL1h 0x00000005
|
||||
#define PSR_M_EL2t 0x00000008
|
||||
#define PSR_M_EL2h 0x00000009
|
||||
#define PSR_M_64 0x00000000
|
||||
#define PSR_M_32 0x00000010
|
||||
#define PSR_M_MASK 0x0000000f
|
||||
|
||||
#define PSR_T 0x00000020
|
||||
|
||||
#define PSR_AARCH32 0x00000010
|
||||
#define PSR_F 0x00000040
|
||||
#define PSR_I 0x00000080
|
||||
|
@ -81,6 +81,10 @@ __ElfType(Auxinfo);
|
||||
#define ELF_TARG_VER 1
|
||||
#endif
|
||||
|
||||
#if __ELF_WORD_SIZE == 32
|
||||
#define ET_DYN_LOAD_ADDR 0x12000
|
||||
#else
|
||||
#define ET_DYN_LOAD_ADDR 0x100000
|
||||
#endif
|
||||
|
||||
#endif /* !_MACHINE_ELF_H_ */
|
||||
|
@ -70,6 +70,14 @@ struct frame {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
#ifdef COMPAT_FREEBSD32
|
||||
struct sigframe32 {
|
||||
struct siginfo32 sf_si;
|
||||
ucontext32_t sf_uc;
|
||||
mcontext32_vfp_t sf_vfp;
|
||||
};
|
||||
#endif /* COMPAT_FREEBSD32 */
|
||||
|
||||
#endif /* !LOCORE */
|
||||
|
||||
#endif /* !_MACHINE_FRAME_H_ */
|
||||
|
@ -42,7 +42,11 @@ struct reg {
|
||||
};
|
||||
|
||||
struct reg32 {
|
||||
int dummy;
|
||||
unsigned int r[13];
|
||||
unsigned int r_sp;
|
||||
unsigned int r_lr;
|
||||
unsigned int r_pc;
|
||||
unsigned int r_cpsr;
|
||||
};
|
||||
|
||||
struct fpreg {
|
||||
|
@ -61,4 +61,30 @@ struct __mcontext {
|
||||
|
||||
typedef struct __mcontext mcontext_t;
|
||||
|
||||
#ifdef COMPAT_FREEBSD32
|
||||
#include <compat/freebsd32/freebsd32_signal.h>
|
||||
typedef struct __mcontext32 {
|
||||
uint32_t mc_gregset[17];
|
||||
uint32_t mc_vfp_size;
|
||||
uint32_t mc_vfp_ptr;
|
||||
uint32_t mc_spare[33];
|
||||
} mcontext32_t;
|
||||
|
||||
typedef struct __ucontext32 {
|
||||
sigset_t uc_sigmask;
|
||||
mcontext32_t uc_mcontext;
|
||||
u_int32_t uc_link;
|
||||
struct sigaltstack32 uc_stack;
|
||||
u_int32_t uc_flags;
|
||||
u_int32_t __spare__[4];
|
||||
} ucontext32_t;
|
||||
|
||||
typedef struct __mcontext32_vfp {
|
||||
__uint64_t mcv_reg[32];
|
||||
__uint32_t mcv_fpscr;
|
||||
} mcontext32_vfp_t;
|
||||
|
||||
#endif /* COMPAT_FREEBSD32 */
|
||||
|
||||
|
||||
#endif /* !_MACHINE_UCONTEXT_H_ */
|
||||
|
@ -65,6 +65,11 @@ int fpu_kern_leave(struct thread *, struct fpu_kern_ctx *);
|
||||
int fpu_kern_thread(u_int);
|
||||
int is_fpu_kern_thread(u_int);
|
||||
|
||||
/* Convert to and from Aarch32 FPSCR to Aarch64 FPCR/FPSR */
|
||||
#define VFP_FPSCR_FROM_SRCR(vpsr, vpcr) ((vpsr) | ((vpcr) & 0x7c00000))
|
||||
#define VFP_FPSR_FROM_FPSCR(vpscr) ((vpscr) &~ 0x7c00000)
|
||||
#define VFP_FPCR_FROM_FPSCR(vpsrc) ((vpsrc) & 0x7c00000)
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user