1 /*- 2 * Copyright (c) 2018 Olivier Houchard 3 * Copyright (c) 2017 Nuxi, https://nuxi.nl/ 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/types.h> 31 #include <sys/proc.h> 32 #include <sys/lock.h> 33 #include <sys/mutex.h> 34 #include <sys/syscallsubr.h> 35 #include <sys/ktr.h> 36 #include <sys/sysent.h> 37 #include <machine/armreg.h> 38 #ifdef VFP 39 #include <machine/vfp.h> 40 #endif 41 #include <compat/freebsd32/freebsd32_proto.h> 42 #include <compat/freebsd32/freebsd32_signal.h> 43 44 extern void freebsd32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask); 45 46 /* 47 * The first two fields of a ucontext_t are the signal mask and the machine 48 * context. The next field is uc_link; we want to avoid destroying the link 49 * when copying out contexts. 50 */ 51 #define UC32_COPY_SIZE offsetof(ucontext32_t, uc_link) 52 53 #ifdef VFP 54 static void get_fpcontext32(struct thread *td, mcontext32_vfp_t *); 55 #endif 56 57 /* 58 * Stubs for machine dependent 32-bits system calls. 59 */ 60 61 int 62 freebsd32_sysarch(struct thread *td, struct freebsd32_sysarch_args *uap) 63 { 64 int error; 65 66 #define ARM_SYNC_ICACHE 0 67 #define ARM_DRAIN_WRITEBUF 1 68 #define ARM_SET_TP 2 69 #define ARM_GET_TP 3 70 #define ARM_GET_VFPSTATE 4 71 72 switch(uap->op) { 73 case ARM_SET_TP: 74 WRITE_SPECIALREG(TPIDR_EL0, uap->parms); 75 WRITE_SPECIALREG(TPIDRRO_EL0, uap->parms); 76 return 0; 77 case ARM_SYNC_ICACHE: 78 { 79 struct { 80 uint32_t addr; 81 uint32_t size; 82 } args; 83 84 if ((error = copyin(uap->parms, &args, sizeof(args))) != 0) 85 return (error); 86 if ((uint64_t)args.addr + (uint64_t)args.size > 0xffffffff) 87 return (EINVAL); 88 cpu_icache_sync_range_checked(args.addr, args.size); 89 return 0; 90 } 91 case ARM_GET_VFPSTATE: 92 { 93 mcontext32_vfp_t mcontext_vfp; 94 95 struct { 96 uint32_t mc_vfp_size; 97 uint32_t mc_vfp; 98 } args; 99 if ((error = copyin(uap->parms, &args, sizeof(args))) != 0) 100 return (error); 101 if (args.mc_vfp_size != sizeof(mcontext_vfp)) 102 return (EINVAL); 103 #ifdef VFP 104 get_fpcontext32(td, &mcontext_vfp); 105 #else 106 bzero(&mcontext_vfp, sizeof(mcontext_vfp)); 107 #endif 108 error = copyout(&mcontext_vfp, 109 (void *)(uintptr_t)args.mc_vfp, 110 sizeof(mcontext_vfp)); 111 return error; 112 } 113 } 114 115 return (EINVAL); 116 } 117 118 119 120 #ifdef VFP 121 static void 122 get_fpcontext32(struct thread *td, mcontext32_vfp_t *mcp) 123 { 124 struct pcb *curpcb; 125 int i; 126 127 critical_enter(); 128 curpcb = curthread->td_pcb; 129 130 if ((curpcb->pcb_fpflags & PCB_FP_STARTED) != 0) { 131 /* 132 * If we have just been running VFP instructions we will 133 * need to save the state to memcpy it below. 134 */ 135 vfp_save_state(td, curpcb); 136 137 KASSERT(curpcb->pcb_fpusaved == &curpcb->pcb_fpustate, 138 ("Called get_fpcontext while the kernel is using the VFP")); 139 KASSERT((curpcb->pcb_fpflags & ~PCB_FP_USERMASK) == 0, 140 ("Non-userspace FPU flags set in get_fpcontext")); 141 for (i = 0; i < 32; i++) 142 mcp->mcv_reg[i] = (uint64_t)curpcb->pcb_fpustate.vfp_regs[i]; 143 mcp->mcv_fpscr = VFP_FPSCR_FROM_SRCR(curpcb->pcb_fpustate.vfp_fpcr, 144 curpcb->pcb_fpustate.vfp_fpsr); 145 } 146 critical_exit(); 147 } 148 149 static void 150 set_fpcontext32(struct thread *td, mcontext32_vfp_t *mcp) 151 { 152 struct pcb *pcb; 153 int i; 154 155 critical_enter(); 156 pcb = td->td_pcb; 157 if (td == curthread) 158 vfp_discard(td); 159 for (i = 0; i < 32; i++) 160 pcb->pcb_fpustate.vfp_regs[i] = mcp->mcv_reg[i]; 161 pcb->pcb_fpustate.vfp_fpsr = VFP_FPSR_FROM_FPSCR(mcp->mcv_fpscr); 162 pcb->pcb_fpustate.vfp_fpcr = VFP_FPSR_FROM_FPSCR(mcp->mcv_fpscr); 163 critical_exit(); 164 } 165 #endif 166 static void 167 get_mcontext32(struct thread *td, mcontext32_t *mcp, int flags) 168 { 169 struct pcb *pcb; 170 struct trapframe *tf; 171 int i; 172 173 pcb = td->td_pcb; 174 tf = td->td_frame; 175 176 if ((flags & GET_MC_CLEAR_RET) != 0) { 177 mcp->mc_gregset[0] = 0; 178 mcp->mc_gregset[16] = tf->tf_spsr & ~PSR_C; 179 } else { 180 mcp->mc_gregset[0] = tf->tf_x[0]; 181 mcp->mc_gregset[16] = tf->tf_spsr; 182 } 183 for (i = 1; i < 15; i++) 184 mcp->mc_gregset[i] = tf->tf_x[i]; 185 mcp->mc_gregset[15] = tf->tf_elr; 186 187 mcp->mc_vfp_size = 0; 188 mcp->mc_vfp_ptr = 0; 189 190 memset(mcp->mc_spare, 0, sizeof(mcp->mc_spare)); 191 } 192 193 static int 194 set_mcontext32(struct thread *td, mcontext32_t *mcp) 195 { 196 struct trapframe *tf; 197 mcontext32_vfp_t mc_vfp; 198 int i; 199 200 tf = td->td_frame; 201 202 for (i = 0; i < 15; i++) 203 tf->tf_x[i] = mcp->mc_gregset[i]; 204 tf->tf_elr = mcp->mc_gregset[15]; 205 tf->tf_spsr = mcp->mc_gregset[16]; 206 #ifdef VFP 207 if (mcp->mc_vfp_size == sizeof(mc_vfp) && mcp->mc_vfp_ptr != 0) { 208 if (copyin((void *)(uintptr_t)mcp->mc_vfp_ptr, &mc_vfp, 209 sizeof(mc_vfp)) != 0) 210 return (EFAULT); 211 set_fpcontext32(td, &mc_vfp); 212 } 213 #endif 214 215 return (0); 216 } 217 218 #define UC_COPY_SIZE offsetof(ucontext32_t, uc_link) 219 220 int 221 freebsd32_getcontext(struct thread *td, struct freebsd32_getcontext_args *uap) 222 { 223 ucontext32_t uc; 224 int ret; 225 226 if (uap->ucp == NULL) 227 ret = EINVAL; 228 else { 229 memset(&uc, 0, sizeof(uc)); 230 get_mcontext32(td, &uc.uc_mcontext, GET_MC_CLEAR_RET); 231 PROC_LOCK(td->td_proc); 232 uc.uc_sigmask = td->td_sigmask; 233 PROC_UNLOCK(td->td_proc); 234 ret = copyout(&uc, uap->ucp, UC_COPY_SIZE); 235 } 236 return (ret); 237 } 238 239 int 240 freebsd32_setcontext(struct thread *td, struct freebsd32_setcontext_args *uap) 241 { 242 ucontext32_t uc; 243 int ret; 244 245 if (uap->ucp == NULL) 246 ret = EINVAL; 247 else { 248 ret = copyin(uap->ucp, &uc, UC_COPY_SIZE); 249 if (ret == 0) { 250 ret = set_mcontext32(td, &uc.uc_mcontext); 251 if (ret == 0) 252 kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, 253 NULL, 0); 254 } 255 } 256 return (ret); 257 } 258 259 int 260 freebsd32_sigreturn(struct thread *td, struct freebsd32_sigreturn_args *uap) 261 { 262 ucontext32_t uc; 263 int error; 264 265 if (uap == NULL) 266 return (EFAULT); 267 if (copyin(uap->sigcntxp, &uc, sizeof(uc))) 268 return (EFAULT); 269 error = set_mcontext32(td, &uc.uc_mcontext); 270 if (error != 0) 271 return (0); 272 273 /* Restore signal mask. */ 274 kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0); 275 276 return (EJUSTRETURN); 277 278 } 279 280 int 281 freebsd32_swapcontext(struct thread *td, struct freebsd32_swapcontext_args *uap) 282 { 283 ucontext32_t uc; 284 int ret; 285 286 if (uap->oucp == NULL || uap->ucp == NULL) 287 ret = EINVAL; 288 else { 289 bzero(&uc, sizeof(uc)); 290 get_mcontext32(td, &uc.uc_mcontext, GET_MC_CLEAR_RET); 291 PROC_LOCK(td->td_proc); 292 uc.uc_sigmask = td->td_sigmask; 293 PROC_UNLOCK(td->td_proc); 294 ret = copyout(&uc, uap->oucp, UC32_COPY_SIZE); 295 if (ret == 0) { 296 ret = copyin(uap->ucp, &uc, UC32_COPY_SIZE); 297 if (ret == 0) { 298 ret = set_mcontext32(td, &uc.uc_mcontext); 299 kern_sigprocmask(td, SIG_SETMASK, 300 &uc.uc_sigmask, NULL, 0); 301 } 302 } 303 } 304 return (ret); 305 } 306 307 void 308 freebsd32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) 309 { 310 struct thread *td; 311 struct proc *p; 312 struct trapframe *tf; 313 struct sigframe32 *fp, frame; 314 struct sigacts *psp; 315 struct siginfo32 siginfo; 316 struct sysentvec *sysent; 317 int onstack; 318 int sig; 319 int code; 320 321 siginfo_to_siginfo32(&ksi->ksi_info, &siginfo); 322 td = curthread; 323 p = td->td_proc; 324 PROC_LOCK_ASSERT(p, MA_OWNED); 325 sig = ksi->ksi_signo; 326 code = ksi->ksi_code; 327 psp = p->p_sigacts; 328 mtx_assert(&psp->ps_mtx, MA_OWNED); 329 tf = td->td_frame; 330 onstack = sigonstack(tf->tf_x[13]); 331 332 CTR4(KTR_SIG, "sendsig: td=%p (%s) catcher=%p sig=%d", td, p->p_comm, 333 catcher, sig); 334 335 /* Allocate and validate space for the signal handler context. */ 336 if ((td->td_pflags & TDP_ALTSTACK) != 0 && !(onstack) && 337 SIGISMEMBER(psp->ps_sigonstack, sig)) { 338 fp = (struct sigframe32 *)((uintptr_t)td->td_sigstk.ss_sp + 339 td->td_sigstk.ss_size); 340 #if defined(COMPAT_43) 341 td->td_sigstk.ss_flags |= SS_ONSTACK; 342 #endif 343 } else 344 fp = (struct sigframe32 *)td->td_frame->tf_x[13]; 345 346 /* make room on the stack */ 347 fp--; 348 349 /* make the stack aligned */ 350 fp = (struct sigframe32 *)((unsigned long)(fp) &~ (8 - 1)); 351 /* Populate the siginfo frame. */ 352 get_mcontext32(td, &frame.sf_uc.uc_mcontext, 0); 353 #ifdef VFP 354 get_fpcontext32(td, &frame.sf_vfp); 355 frame.sf_uc.uc_mcontext.mc_vfp_size = sizeof(fp->sf_vfp); 356 frame.sf_uc.uc_mcontext.mc_vfp_ptr = (uint32_t)(uintptr_t)&fp->sf_vfp; 357 #else 358 frame.sf_uc.uc_mcontext.mc_vfp_size = 0; 359 frame.sf_uc.uc_mcontext.mc_vfp_ptr = (uint32_t)NULL; 360 #endif 361 frame.sf_si = siginfo; 362 frame.sf_uc.uc_sigmask = *mask; 363 frame.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK ) 364 ? ((onstack) ? SS_ONSTACK : 0) : SS_DISABLE; 365 frame.sf_uc.uc_stack.ss_sp = (uintptr_t)td->td_sigstk.ss_sp; 366 frame.sf_uc.uc_stack.ss_size = td->td_sigstk.ss_size; 367 368 mtx_unlock(&psp->ps_mtx); 369 PROC_UNLOCK(td->td_proc); 370 371 /* Copy the sigframe out to the user's stack. */ 372 if (copyout(&frame, fp, sizeof(*fp)) != 0) { 373 /* Process has trashed its stack. Kill it. */ 374 CTR2(KTR_SIG, "sendsig: sigexit td=%p fp=%p", td, fp); 375 PROC_LOCK(p); 376 sigexit(td, SIGILL); 377 } 378 379 /* 380 * Build context to run handler in. We invoke the handler 381 * directly, only returning via the trampoline. Note the 382 * trampoline version numbers are coordinated with machine- 383 * dependent code in libc. 384 */ 385 386 tf->tf_x[0] = sig; 387 tf->tf_x[1] = (register_t)&fp->sf_si; 388 tf->tf_x[2] = (register_t)&fp->sf_uc; 389 390 /* the trampoline uses r5 as the uc address */ 391 tf->tf_x[5] = (register_t)&fp->sf_uc; 392 tf->tf_elr = (register_t)catcher; 393 tf->tf_x[13] = (register_t)fp; 394 sysent = p->p_sysent; 395 if (sysent->sv_sigcode_base != 0) 396 tf->tf_x[14] = (register_t)sysent->sv_sigcode_base; 397 else 398 tf->tf_x[14] = (register_t)(sysent->sv_psstrings - 399 *(sysent->sv_szsigcode)); 400 /* Set the mode to enter in the signal handler */ 401 if ((register_t)catcher & 1) 402 tf->tf_spsr |= PSR_T; 403 else 404 tf->tf_spsr &= ~PSR_T; 405 406 CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_x[14], 407 tf->tf_x[13]); 408 409 PROC_LOCK(p); 410 mtx_lock(&psp->ps_mtx); 411 412 } 413