1/*- 2 * Copyright (c) 2014, 2015 The FreeBSD Foundation. 3 * Copyright (c) 2014, 2017 Andrew Turner. 4 * Copyright (c) 2018 Olivier Houchard 5 * All rights reserved. 6 * 7 * This software was developed by Andrew Turner under 8 * sponsorship from the FreeBSD Foundation. 9 * 10 * Portions of this software were developed by Konstantin Belousov 11 * under sponsorship from the FreeBSD Foundation. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35#include <sys/cdefs.h> 36#define __ELF_WORD_SIZE 32 37 38#include <sys/param.h> 39#include <sys/kernel.h> 40#include <sys/systm.h> 41#include <sys/exec.h> 42#include <sys/imgact.h> 43#include <sys/linker.h> 44#include <sys/proc.h> 45#include <sys/reg.h> 46#include <sys/sysctl.h> 47#include <sys/sysent.h> 48#include <sys/imgact_elf.h> 49#include <sys/syscall.h> 50#include <sys/signalvar.h> 51#include <sys/vnode.h> 52 53#include <machine/elf.h> 54#include <machine/pcb.h> 55#ifdef VFP 56#include <machine/vfp.h> 57#endif 58 59#include <compat/freebsd32/freebsd32_util.h> 60 61#define FREEBSD32_MINUSER 0x00001000 62#define FREEBSD32_MAXUSER ((1ul << 32) - PAGE_SIZE) 63#define FREEBSD32_SHAREDPAGE (FREEBSD32_MAXUSER - PAGE_SIZE) 64#define FREEBSD32_USRSTACK FREEBSD32_SHAREDPAGE 65#define AARCH32_MAXDSIZ (512 * 1024 * 1024) 66#define AARCH32_MAXSSIZ (64 * 1024 * 1024) 67#define AARCH32_MAXVMEM 0 68 69extern const char *freebsd32_syscallnames[]; 70 71extern char aarch32_sigcode[]; 72extern int sz_aarch32_sigcode; 73 74static int freebsd32_fetch_syscall_args(struct thread *td); 75static void freebsd32_setregs(struct thread *td, struct image_params *imgp, 76 u_long stack); 77static void freebsd32_set_syscall_retval(struct thread *, int); 78 79static bool elf32_arm_abi_supported(const struct image_params *, 80 const int32_t *, const uint32_t *); 81static void elf32_fixlimit(struct rlimit *rl, int which); 82 83extern void freebsd32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask); 84 85u_long __read_frequently elf32_hwcap; 86u_long __read_frequently elf32_hwcap2; 87 88static SYSCTL_NODE(_compat, OID_AUTO, aarch32, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 89 "aarch32 mode"); 90 91static u_long aarch32_maxdsiz = AARCH32_MAXDSIZ; 92SYSCTL_ULONG(_compat_aarch32, OID_AUTO, maxdsiz, CTLFLAG_RWTUN, 93 &aarch32_maxdsiz, 0, ""); 94u_long aarch32_maxssiz = AARCH32_MAXSSIZ; 95SYSCTL_ULONG(_compat_aarch32, OID_AUTO, maxssiz, CTLFLAG_RWTUN, 96 &aarch32_maxssiz, 0, ""); 97static u_long aarch32_maxvmem = AARCH32_MAXVMEM; 98SYSCTL_ULONG(_compat_aarch32, OID_AUTO, maxvmem, CTLFLAG_RWTUN, 99 &aarch32_maxvmem, 0, ""); 100 101static struct sysentvec elf32_freebsd_sysvec = { 102 .sv_size = SYS_MAXSYSCALL, 103 .sv_table = freebsd32_sysent, 104 .sv_fixup = elf32_freebsd_fixup, 105 .sv_sendsig = freebsd32_sendsig, 106 .sv_sigcode = aarch32_sigcode, 107 .sv_szsigcode = &sz_aarch32_sigcode, 108 .sv_name = "FreeBSD ELF32", 109 .sv_coredump = elf32_coredump, 110 .sv_elf_core_osabi = ELFOSABI_FREEBSD, 111 .sv_elf_core_abi_vendor = FREEBSD_ABI_VENDOR, 112 .sv_elf_core_prepare_notes = elf32_prepare_notes, 113 .sv_minsigstksz = MINSIGSTKSZ, 114 .sv_minuser = FREEBSD32_MINUSER, 115 .sv_maxuser = FREEBSD32_MAXUSER, 116 .sv_usrstack = FREEBSD32_USRSTACK, 117 .sv_psstrings = FREEBSD32_PS_STRINGS, 118 .sv_psstringssz = sizeof(struct freebsd32_ps_strings), 119 .sv_stackprot = VM_PROT_READ | VM_PROT_WRITE, 120 .sv_copyout_auxargs = elf32_freebsd_copyout_auxargs, 121 .sv_copyout_strings = freebsd32_copyout_strings, 122 .sv_setregs = freebsd32_setregs, 123 .sv_fixlimit = elf32_fixlimit, 124 .sv_maxssiz = &aarch32_maxssiz, 125 .sv_flags = SV_ABI_FREEBSD | SV_ILP32 | SV_SHP | SV_TIMEKEEP | 126 SV_RNG_SEED_VER | SV_SIGSYS, 127 .sv_set_syscall_retval = freebsd32_set_syscall_retval, 128 .sv_fetch_syscall_args = freebsd32_fetch_syscall_args, 129 .sv_syscallnames = freebsd32_syscallnames, 130 .sv_shared_page_base = FREEBSD32_SHAREDPAGE, 131 .sv_shared_page_len = PAGE_SIZE, 132 .sv_schedtail = NULL, 133 .sv_thread_detach = NULL, 134 .sv_trap = NULL, 135 .sv_hwcap = &elf32_hwcap, 136 .sv_hwcap2 = &elf32_hwcap2, 137 .sv_onexec_old = exec_onexec_old, 138 .sv_onexit = exit_onexit, 139 .sv_regset_begin = SET_BEGIN(__elfN(regset)), 140 .sv_regset_end = SET_LIMIT(__elfN(regset)), 141}; 142INIT_SYSENTVEC(elf32_sysvec, &elf32_freebsd_sysvec); 143 144static Elf32_Brandinfo freebsd32_brand_info = { 145 .brand = ELFOSABI_FREEBSD, 146 .machine = EM_ARM, 147 .compat_3_brand = "FreeBSD", 148 .interp_path = "/libexec/ld-elf.so.1", 149 .sysvec = &elf32_freebsd_sysvec, 150 .interp_newpath = "/libexec/ld-elf32.so.1", 151 .brand_note = &elf32_freebsd_brandnote, 152 .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE, 153 .header_supported= elf32_arm_abi_supported, 154}; 155 156static void 157register_elf32_brand(void *arg) 158{ 159 /* Check if we support AArch32 */ 160 if (ID_AA64PFR0_EL0_VAL(READ_SPECIALREG(id_aa64pfr0_el1)) == 161 ID_AA64PFR0_EL0_64_32) { 162 elf32_insert_brand_entry(&freebsd32_brand_info); 163 } else { 164 compat_freebsd_32bit = 0; 165 } 166} 167SYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_FIRST, register_elf32_brand, NULL); 168 169static bool 170elf32_arm_abi_supported(const struct image_params *imgp, 171 const int32_t *osrel __unused, const uint32_t *fctl0 __unused) 172{ 173 const Elf32_Ehdr *hdr; 174 175#define EF_ARM_EABI_FREEBSD_MIN EF_ARM_EABI_VER4 176 hdr = (const Elf32_Ehdr *)imgp->image_header; 177 if (EF_ARM_EABI_VERSION(hdr->e_flags) < EF_ARM_EABI_FREEBSD_MIN) { 178 if (bootverbose) 179 uprintf("Attempting to execute non EABI binary " 180 "(rev %d) image %s", 181 EF_ARM_EABI_VERSION(hdr->e_flags), 182 imgp->args->fname); 183 return (false); 184 } 185 186 return (true); 187} 188 189static int 190freebsd32_fetch_syscall_args(struct thread *td) 191{ 192 struct proc *p; 193 register_t *ap; 194 struct syscall_args *sa; 195 int error, i, nap, narg; 196 unsigned int args[4]; 197 198 nap = 4; 199 p = td->td_proc; 200 ap = td->td_frame->tf_x; 201 sa = &td->td_sa; 202 203 /* r7 is the syscall id */ 204 sa->code = td->td_frame->tf_x[7]; 205 sa->original_code = sa->code; 206 207 if (sa->code == SYS_syscall) { 208 sa->code = *ap++; 209 nap--; 210 } else if (sa->code == SYS___syscall) { 211 sa->code = ap[1]; 212 nap -= 2; 213 ap += 2; 214 } 215 216 if (sa->code >= p->p_sysent->sv_size) 217 sa->callp = &nosys_sysent; 218 else 219 sa->callp = &p->p_sysent->sv_table[sa->code]; 220 221 narg = sa->callp->sy_narg; 222 for (i = 0; i < nap; i++) 223 sa->args[i] = ap[i]; 224 if (narg > nap) { 225 if (narg - nap > nitems(args)) 226 panic("Too many system call arguiments"); 227 error = copyin((void *)td->td_frame->tf_x[13], args, 228 (narg - nap) * sizeof(int)); 229 if (error != 0) 230 return (error); 231 for (i = 0; i < (narg - nap); i++) 232 sa->args[i + nap] = args[i]; 233 } 234 235 td->td_retval[0] = 0; 236 td->td_retval[1] = 0; 237 238 return (0); 239} 240 241static void 242freebsd32_set_syscall_retval(struct thread *td, int error) 243{ 244 struct trapframe *frame; 245 246 frame = td->td_frame; 247 switch (error) { 248 case 0: 249 frame->tf_x[0] = td->td_retval[0]; 250 frame->tf_x[1] = td->td_retval[1]; 251 frame->tf_spsr &= ~PSR_C; 252 break; 253 case ERESTART: 254 /* 255 * Reconstruct the pc to point at the swi. 256 */ 257 if ((frame->tf_spsr & PSR_T) != 0) 258 frame->tf_elr -= 2; //THUMB_INSN_SIZE; 259 else 260 frame->tf_elr -= 4; //INSN_SIZE; 261 break; 262 case EJUSTRETURN: 263 /* nothing to do */ 264 break; 265 default: 266 frame->tf_x[0] = error; 267 frame->tf_spsr |= PSR_C; 268 break; 269 } 270} 271 272static void 273freebsd32_setregs(struct thread *td, struct image_params *imgp, 274 uintptr_t stack) 275{ 276 struct trapframe *tf = td->td_frame; 277 struct pcb *pcb = td->td_pcb; 278 279 memset(tf, 0, sizeof(struct trapframe)); 280 281 /* 282 * We need to set x0 for init as it doesn't call 283 * cpu_set_syscall_retval to copy the value. We also 284 * need to set td_retval for the cases where we do. 285 */ 286 tf->tf_x[0] = stack; 287 /* SP_usr is mapped to x13 */ 288 tf->tf_x[13] = stack; 289 /* LR_usr is mapped to x14 */ 290 tf->tf_x[14] = imgp->entry_addr; 291 tf->tf_elr = imgp->entry_addr; 292 tf->tf_spsr = PSR_M_32; 293 if ((uint32_t)imgp->entry_addr & 1) 294 tf->tf_spsr |= PSR_T; 295 296#ifdef VFP 297 vfp_reset_state(td, pcb); 298#endif 299 300 /* 301 * Clear debug register state. It is not applicable to the new process. 302 */ 303 bzero(&pcb->pcb_dbg_regs, sizeof(pcb->pcb_dbg_regs)); 304} 305 306void 307elf32_dump_thread(struct thread *td, void *dst, size_t *off) 308{ 309} 310 311static void 312elf32_fixlimit(struct rlimit *rl, int which) 313{ 314 315 switch (which) { 316 case RLIMIT_DATA: 317 if (aarch32_maxdsiz != 0) { 318 if (rl->rlim_cur > aarch32_maxdsiz) 319 rl->rlim_cur = aarch32_maxdsiz; 320 if (rl->rlim_max > aarch32_maxdsiz) 321 rl->rlim_max = aarch32_maxdsiz; 322 } 323 break; 324 case RLIMIT_STACK: 325 if (aarch32_maxssiz != 0) { 326 if (rl->rlim_cur > aarch32_maxssiz) 327 rl->rlim_cur = aarch32_maxssiz; 328 if (rl->rlim_max > aarch32_maxssiz) 329 rl->rlim_max = aarch32_maxssiz; 330 } 331 break; 332 case RLIMIT_VMEM: 333 if (aarch32_maxvmem != 0) { 334 if (rl->rlim_cur > aarch32_maxvmem) 335 rl->rlim_cur = aarch32_maxvmem; 336 if (rl->rlim_max > aarch32_maxvmem) 337 rl->rlim_max = aarch32_maxvmem; 338 } 339 break; 340 } 341} 342