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 __FBSDID("$FreeBSD$"); 37 38 #define __ELF_WORD_SIZE 32 39 40 #include <sys/param.h> 41 #include <sys/kernel.h> 42 #include <sys/systm.h> 43 #include <sys/exec.h> 44 #include <sys/imgact.h> 45 #include <sys/linker.h> 46 #include <sys/proc.h> 47 #include <sys/reg.h> 48 #include <sys/sysent.h> 49 #include <sys/imgact_elf.h> 50 #include <sys/syscall.h> 51 #include <sys/signalvar.h> 52 #include <sys/vnode.h> 53 54 #include <machine/elf.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 66 extern const char *freebsd32_syscallnames[]; 67 68 extern char aarch32_sigcode[]; 69 extern int sz_aarch32_sigcode; 70 71 static int freebsd32_fetch_syscall_args(struct thread *td); 72 static void freebsd32_setregs(struct thread *td, struct image_params *imgp, 73 u_long stack); 74 static void freebsd32_set_syscall_retval(struct thread *, int); 75 76 static boolean_t elf32_arm_abi_supported(struct image_params *, int32_t *, 77 uint32_t *); 78 79 extern void freebsd32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask); 80 81 u_long __read_frequently elf32_hwcap; 82 u_long __read_frequently elf32_hwcap2; 83 84 static struct sysentvec elf32_freebsd_sysvec = { 85 .sv_size = SYS_MAXSYSCALL, 86 .sv_table = freebsd32_sysent, 87 .sv_transtrap = NULL, 88 .sv_fixup = elf32_freebsd_fixup, 89 .sv_sendsig = freebsd32_sendsig, 90 .sv_sigcode = aarch32_sigcode, 91 .sv_szsigcode = &sz_aarch32_sigcode, 92 .sv_name = "FreeBSD ELF32", 93 .sv_coredump = elf32_coredump, 94 .sv_elf_core_osabi = ELFOSABI_FREEBSD, 95 .sv_elf_core_abi_vendor = FREEBSD_ABI_VENDOR, 96 .sv_elf_core_prepare_notes = elf32_prepare_notes, 97 .sv_imgact_try = NULL, 98 .sv_minsigstksz = MINSIGSTKSZ, 99 .sv_minuser = FREEBSD32_MINUSER, 100 .sv_maxuser = FREEBSD32_MAXUSER, 101 .sv_usrstack = FREEBSD32_USRSTACK, 102 .sv_psstrings = FREEBSD32_PS_STRINGS, 103 .sv_psstringssz = sizeof(struct freebsd32_ps_strings), 104 .sv_stackprot = VM_PROT_READ | VM_PROT_WRITE, 105 .sv_copyout_auxargs = elf32_freebsd_copyout_auxargs, 106 .sv_copyout_strings = freebsd32_copyout_strings, 107 .sv_setregs = freebsd32_setregs, 108 .sv_fixlimit = NULL, // XXX 109 .sv_maxssiz = NULL, 110 .sv_flags = SV_ABI_FREEBSD | SV_ILP32 | SV_SHP | SV_TIMEKEEP | 111 SV_RNG_SEED_VER, 112 .sv_set_syscall_retval = freebsd32_set_syscall_retval, 113 .sv_fetch_syscall_args = freebsd32_fetch_syscall_args, 114 .sv_syscallnames = freebsd32_syscallnames, 115 .sv_shared_page_base = FREEBSD32_SHAREDPAGE, 116 .sv_shared_page_len = PAGE_SIZE, 117 .sv_schedtail = NULL, 118 .sv_thread_detach = NULL, 119 .sv_trap = NULL, 120 .sv_hwcap = &elf32_hwcap, 121 .sv_hwcap2 = &elf32_hwcap2, 122 .sv_onexec_old = exec_onexec_old, 123 .sv_onexit = exit_onexit, 124 .sv_regset_begin = SET_BEGIN(__elfN(regset)), 125 .sv_regset_end = SET_LIMIT(__elfN(regset)), 126 }; 127 INIT_SYSENTVEC(elf32_sysvec, &elf32_freebsd_sysvec); 128 129 static Elf32_Brandinfo freebsd32_brand_info = { 130 .brand = ELFOSABI_FREEBSD, 131 .machine = EM_ARM, 132 .compat_3_brand = "FreeBSD", 133 .emul_path = NULL, 134 .interp_path = "/libexec/ld-elf.so.1", 135 .sysvec = &elf32_freebsd_sysvec, 136 .interp_newpath = "/libexec/ld-elf32.so.1", 137 .brand_note = &elf32_freebsd_brandnote, 138 .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE, 139 .header_supported= elf32_arm_abi_supported, 140 }; 141 142 SYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_FIRST, 143 (sysinit_cfunc_t)elf32_insert_brand_entry, &freebsd32_brand_info); 144 145 static boolean_t 146 elf32_arm_abi_supported(struct image_params *imgp, int32_t *osrel __unused, 147 uint32_t *fctl0 __unused) 148 { 149 const Elf32_Ehdr *hdr; 150 151 /* Check if we support AArch32 */ 152 if (ID_AA64PFR0_EL0_VAL(READ_SPECIALREG(id_aa64pfr0_el1)) != 153 ID_AA64PFR0_EL0_64_32) 154 return (FALSE); 155 156 #define EF_ARM_EABI_VERSION(x) (((x) & EF_ARM_EABIMASK) >> 24) 157 #define EF_ARM_EABI_FREEBSD_MIN 4 158 hdr = (const Elf32_Ehdr *)imgp->image_header; 159 if (EF_ARM_EABI_VERSION(hdr->e_flags) < EF_ARM_EABI_FREEBSD_MIN) { 160 if (bootverbose) 161 uprintf("Attempting to execute non EABI binary " 162 "(rev %d) image %s", 163 EF_ARM_EABI_VERSION(hdr->e_flags), 164 imgp->args->fname); 165 return (FALSE); 166 } 167 168 return (TRUE); 169 } 170 171 static int 172 freebsd32_fetch_syscall_args(struct thread *td) 173 { 174 struct proc *p; 175 register_t *ap; 176 struct syscall_args *sa; 177 int error, i, nap, narg; 178 unsigned int args[4]; 179 180 nap = 4; 181 p = td->td_proc; 182 ap = td->td_frame->tf_x; 183 sa = &td->td_sa; 184 185 /* r7 is the syscall id */ 186 sa->code = td->td_frame->tf_x[7]; 187 sa->original_code = sa->code; 188 189 if (sa->code == SYS_syscall) { 190 sa->code = *ap++; 191 nap--; 192 } else if (sa->code == SYS___syscall) { 193 sa->code = ap[1]; 194 nap -= 2; 195 ap += 2; 196 } 197 198 if (sa->code >= p->p_sysent->sv_size) 199 sa->callp = &p->p_sysent->sv_table[0]; 200 else 201 sa->callp = &p->p_sysent->sv_table[sa->code]; 202 203 narg = sa->callp->sy_narg; 204 for (i = 0; i < nap; i++) 205 sa->args[i] = ap[i]; 206 if (narg > nap) { 207 if (narg - nap > nitems(args)) 208 panic("Too many system call arguiments"); 209 error = copyin((void *)td->td_frame->tf_x[13], args, 210 (narg - nap) * sizeof(int)); 211 if (error != 0) 212 return (error); 213 for (i = 0; i < (narg - nap); i++) 214 sa->args[i + nap] = args[i]; 215 } 216 217 td->td_retval[0] = 0; 218 td->td_retval[1] = 0; 219 220 return (0); 221 } 222 223 static void 224 freebsd32_set_syscall_retval(struct thread *td, int error) 225 { 226 struct trapframe *frame; 227 228 frame = td->td_frame; 229 switch (error) { 230 case 0: 231 frame->tf_x[0] = td->td_retval[0]; 232 frame->tf_x[1] = td->td_retval[1]; 233 frame->tf_spsr &= ~PSR_C; 234 break; 235 case ERESTART: 236 /* 237 * Reconstruct the pc to point at the swi. 238 */ 239 if ((frame->tf_spsr & PSR_T) != 0) 240 frame->tf_elr -= 2; //THUMB_INSN_SIZE; 241 else 242 frame->tf_elr -= 4; //INSN_SIZE; 243 break; 244 case EJUSTRETURN: 245 /* nothing to do */ 246 break; 247 default: 248 frame->tf_x[0] = error; 249 frame->tf_spsr |= PSR_C; 250 break; 251 } 252 } 253 254 static void 255 freebsd32_setregs(struct thread *td, struct image_params *imgp, 256 uintptr_t stack) 257 { 258 struct trapframe *tf = td->td_frame; 259 struct pcb *pcb = td->td_pcb; 260 261 memset(tf, 0, sizeof(struct trapframe)); 262 263 /* 264 * We need to set x0 for init as it doesn't call 265 * cpu_set_syscall_retval to copy the value. We also 266 * need to set td_retval for the cases where we do. 267 */ 268 tf->tf_x[0] = stack; 269 /* SP_usr is mapped to x13 */ 270 tf->tf_x[13] = stack; 271 /* LR_usr is mapped to x14 */ 272 tf->tf_x[14] = imgp->entry_addr; 273 tf->tf_elr = imgp->entry_addr; 274 tf->tf_spsr = PSR_M_32; 275 if ((uint32_t)imgp->entry_addr & 1) 276 tf->tf_spsr |= PSR_T; 277 278 #ifdef VFP 279 vfp_reset_state(td, pcb); 280 #endif 281 282 /* 283 * Clear debug register state. It is not applicable to the new process. 284 */ 285 bzero(&pcb->pcb_dbg_regs, sizeof(pcb->pcb_dbg_regs)); 286 } 287 288 void 289 elf32_dump_thread(struct thread *td, void *dst, size_t *off) 290 { 291 } 292