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/param.h> 28 #include <sys/exec.h> 29 #include <sys/proc.h> 30 #include <sys/lock.h> 31 #include <sys/mutex.h> 32 #include <sys/syscallsubr.h> 33 #include <sys/ktr.h> 34 #include <sys/sysctl.h> 35 #include <sys/sysent.h> 36 #include <sys/sysproto.h> 37 #include <machine/armreg.h> 38 #include <machine/pcb.h> 39 #ifdef VFP 40 #include <machine/vfp.h> 41 #endif 42 #include <compat/freebsd32/freebsd32_proto.h> 43 #include <compat/freebsd32/freebsd32_signal.h> 44 45 #include <vm/vm.h> 46 #include <vm/vm_param.h> 47 #include <vm/pmap.h> 48 #include <vm/vm_map.h> 49 50 _Static_assert(sizeof(mcontext32_t) == 208, "mcontext32_t size incorrect"); 51 _Static_assert(sizeof(ucontext32_t) == 260, "ucontext32_t size incorrect"); 52 _Static_assert(sizeof(struct siginfo32) == 64, "struct siginfo32 size incorrect"); 53 54 extern void freebsd32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask); 55 56 SYSCTL_NODE(_compat, OID_AUTO, arm, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 57 "32-bit mode"); 58 59 /* 60 * The first two fields of a ucontext_t are the signal mask and the machine 61 * context. The next field is uc_link; we want to avoid destroying the link 62 * when copying out contexts. 63 */ 64 #define UC32_COPY_SIZE offsetof(ucontext32_t, uc_link) 65 66 /* 67 * Stubs for machine dependent 32-bits system calls. 68 */ 69 70 int 71 freebsd32_sysarch(struct thread *td, struct freebsd32_sysarch_args *uap) 72 { 73 int error; 74 75 #define ARM_SYNC_ICACHE 0 76 #define ARM_DRAIN_WRITEBUF 1 77 #define ARM_SET_TP 2 78 #define ARM_GET_TP 3 79 #define ARM_GET_VFPSTATE 4 80 81 switch(uap->op) { 82 case ARM_SET_TP: 83 WRITE_SPECIALREG(tpidr_el0, uap->parms); 84 WRITE_SPECIALREG(tpidrro_el0, uap->parms); 85 return 0; 86 case ARM_SYNC_ICACHE: 87 { 88 struct { 89 uint32_t addr; 90 uint32_t size; 91 } args; 92 93 if ((error = copyin(uap->parms, &args, sizeof(args))) != 0) 94 return (error); 95 if ((uint64_t)args.addr + (uint64_t)args.size > 0xffffffff) 96 return (EINVAL); 97 cpu_icache_sync_range_checked(args.addr, args.size); 98 return 0; 99 } 100 case ARM_GET_VFPSTATE: 101 { 102 mcontext32_vfp_t mcontext_vfp; 103 104 struct { 105 uint32_t mc_vfp_size; 106 uint32_t mc_vfp; 107 } args; 108 if ((error = copyin(uap->parms, &args, sizeof(args))) != 0) 109 return (error); 110 if (args.mc_vfp_size != sizeof(mcontext_vfp)) 111 return (EINVAL); 112 #ifdef VFP 113 get_fpcontext32(td, &mcontext_vfp); 114 #else 115 bzero(&mcontext_vfp, sizeof(mcontext_vfp)); 116 #endif 117 error = copyout(&mcontext_vfp, 118 (void *)(uintptr_t)args.mc_vfp, 119 sizeof(mcontext_vfp)); 120 return error; 121 } 122 } 123 124 return (EINVAL); 125 } 126 127 #ifdef VFP 128 void 129 get_fpcontext32(struct thread *td, mcontext32_vfp_t *mcp) 130 { 131 struct pcb *pcb; 132 int i; 133 134 KASSERT(td == curthread || TD_IS_SUSPENDED(td) || 135 P_SHOULDSTOP(td->td_proc), 136 ("not suspended thread %p", td)); 137 138 memset(mcp, 0, sizeof(*mcp)); 139 pcb = td->td_pcb; 140 141 if ((pcb->pcb_fpflags & PCB_FP_STARTED) != 0) { 142 /* 143 * If we have just been running VFP instructions we will 144 * need to save the state to memcpy it below. 145 */ 146 if (td == curthread) 147 vfp_save_state(td, pcb); 148 149 KASSERT(pcb->pcb_fpusaved == &pcb->pcb_fpustate, 150 ("Called get_fpcontext32 while the kernel is using the VFP")); 151 KASSERT((pcb->pcb_fpflags & ~PCB_FP_USERMASK) == 0, 152 ("Non-userspace FPU flags set in get_fpcontext32")); 153 for (i = 0; i < 16; i++) { 154 uint64_t *tmpreg = (uint64_t *)&pcb->pcb_fpustate.vfp_regs[i]; 155 156 mcp->mcv_reg[i * 2] = tmpreg[0]; 157 mcp->mcv_reg[i * 2 + 1] = tmpreg[1]; 158 } 159 mcp->mcv_fpscr = VFP_FPSCR_FROM_SRCR(pcb->pcb_fpustate.vfp_fpcr, 160 pcb->pcb_fpustate.vfp_fpsr); 161 } 162 } 163 164 void 165 set_fpcontext32(struct thread *td, mcontext32_vfp_t *mcp) 166 { 167 struct pcb *pcb; 168 int i; 169 170 critical_enter(); 171 pcb = td->td_pcb; 172 if (td == curthread) 173 vfp_discard(td); 174 for (i = 0; i < 16; i++) { 175 uint64_t *tmpreg = (uint64_t *)&pcb->pcb_fpustate.vfp_regs[i]; 176 177 tmpreg[0] = mcp->mcv_reg[i * 2]; 178 tmpreg[1] = mcp->mcv_reg[i * 2 + 1]; 179 } 180 pcb->pcb_fpustate.vfp_fpsr = VFP_FPSR_FROM_FPSCR(mcp->mcv_fpscr); 181 pcb->pcb_fpustate.vfp_fpcr = VFP_FPSR_FROM_FPSCR(mcp->mcv_fpscr); 182 critical_exit(); 183 } 184 #endif 185 186 static void 187 get_mcontext32(struct thread *td, mcontext32_t *mcp, int flags) 188 { 189 struct trapframe *tf; 190 int i; 191 192 tf = td->td_frame; 193 194 if ((flags & GET_MC_CLEAR_RET) != 0) { 195 mcp->mc_gregset[0] = 0; 196 mcp->mc_gregset[16] = tf->tf_spsr & ~PSR_C; 197 } else { 198 mcp->mc_gregset[0] = tf->tf_x[0]; 199 mcp->mc_gregset[16] = tf->tf_spsr; 200 } 201 for (i = 1; i < 15; i++) 202 mcp->mc_gregset[i] = tf->tf_x[i]; 203 mcp->mc_gregset[15] = tf->tf_elr; 204 205 mcp->mc_vfp_size = 0; 206 mcp->mc_vfp_ptr = 0; 207 208 memset(mcp->mc_spare, 0, sizeof(mcp->mc_spare)); 209 } 210 211 static int 212 set_mcontext32(struct thread *td, mcontext32_t *mcp) 213 { 214 struct trapframe *tf; 215 mcontext32_vfp_t mc_vfp; 216 uint32_t spsr; 217 int i; 218 219 tf = td->td_frame; 220 221 spsr = mcp->mc_gregset[16]; 222 /* 223 * There is no PSR_SS in the 32-bit kernel so ignore it if it's set 224 * as we will set it later if needed. 225 */ 226 if ((spsr & ~(PSR_SETTABLE_32 | PSR_SS)) != 227 (tf->tf_spsr & ~(PSR_SETTABLE_32 | PSR_SS))) 228 return (EINVAL); 229 230 spsr &= PSR_SETTABLE_32; 231 spsr |= tf->tf_spsr & ~PSR_SETTABLE_32; 232 233 if ((td->td_dbgflags & TDB_STEP) != 0) { 234 spsr |= PSR_SS; 235 td->td_pcb->pcb_flags |= PCB_SINGLE_STEP; 236 WRITE_SPECIALREG(mdscr_el1, 237 READ_SPECIALREG(mdscr_el1) | MDSCR_SS); 238 } 239 240 for (i = 0; i < 15; i++) 241 tf->tf_x[i] = mcp->mc_gregset[i]; 242 tf->tf_elr = mcp->mc_gregset[15]; 243 tf->tf_spsr = spsr; 244 #ifdef VFP 245 if (mcp->mc_vfp_size == sizeof(mc_vfp) && mcp->mc_vfp_ptr != 0) { 246 if (copyin((void *)(uintptr_t)mcp->mc_vfp_ptr, &mc_vfp, 247 sizeof(mc_vfp)) != 0) 248 return (EFAULT); 249 set_fpcontext32(td, &mc_vfp); 250 } 251 #endif 252 253 return (0); 254 } 255 256 #define UC_COPY_SIZE offsetof(ucontext32_t, uc_link) 257 258 int 259 freebsd32_getcontext(struct thread *td, struct freebsd32_getcontext_args *uap) 260 { 261 ucontext32_t uc; 262 int ret; 263 264 if (uap->ucp == NULL) 265 ret = EINVAL; 266 else { 267 memset(&uc, 0, sizeof(uc)); 268 get_mcontext32(td, &uc.uc_mcontext, GET_MC_CLEAR_RET); 269 PROC_LOCK(td->td_proc); 270 uc.uc_sigmask = td->td_sigmask; 271 PROC_UNLOCK(td->td_proc); 272 ret = copyout(&uc, uap->ucp, UC_COPY_SIZE); 273 } 274 return (ret); 275 } 276 277 int 278 freebsd32_setcontext(struct thread *td, struct freebsd32_setcontext_args *uap) 279 { 280 ucontext32_t uc; 281 int ret; 282 283 if (uap->ucp == NULL) 284 ret = EINVAL; 285 else { 286 ret = copyin(uap->ucp, &uc, UC_COPY_SIZE); 287 if (ret == 0) { 288 ret = set_mcontext32(td, &uc.uc_mcontext); 289 if (ret == 0) 290 kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, 291 NULL, 0); 292 } 293 } 294 return (ret); 295 } 296 297 int 298 freebsd32_sigreturn(struct thread *td, struct freebsd32_sigreturn_args *uap) 299 { 300 ucontext32_t uc; 301 int error; 302 303 if (uap == NULL) 304 return (EFAULT); 305 if (copyin(uap->sigcntxp, &uc, sizeof(uc))) 306 return (EFAULT); 307 error = set_mcontext32(td, &uc.uc_mcontext); 308 if (error != 0) 309 return (0); 310 311 /* Restore signal mask. */ 312 kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0); 313 314 return (EJUSTRETURN); 315 316 } 317 318 int 319 freebsd32_swapcontext(struct thread *td, struct freebsd32_swapcontext_args *uap) 320 { 321 ucontext32_t uc; 322 int ret; 323 324 if (uap->oucp == NULL || uap->ucp == NULL) 325 ret = EINVAL; 326 else { 327 bzero(&uc, sizeof(uc)); 328 get_mcontext32(td, &uc.uc_mcontext, GET_MC_CLEAR_RET); 329 PROC_LOCK(td->td_proc); 330 uc.uc_sigmask = td->td_sigmask; 331 PROC_UNLOCK(td->td_proc); 332 ret = copyout(&uc, uap->oucp, UC32_COPY_SIZE); 333 if (ret == 0) { 334 ret = copyin(uap->ucp, &uc, UC32_COPY_SIZE); 335 if (ret == 0) { 336 ret = set_mcontext32(td, &uc.uc_mcontext); 337 kern_sigprocmask(td, SIG_SETMASK, 338 &uc.uc_sigmask, NULL, 0); 339 } 340 } 341 } 342 return (ret); 343 } 344 345 void 346 freebsd32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) 347 { 348 struct thread *td; 349 struct proc *p; 350 struct trapframe *tf; 351 struct sigframe32 *fp, frame; 352 struct sigacts *psp; 353 struct siginfo32 siginfo; 354 struct sysentvec *sysent; 355 int onstack; 356 int sig; 357 358 siginfo_to_siginfo32(&ksi->ksi_info, &siginfo); 359 td = curthread; 360 p = td->td_proc; 361 PROC_LOCK_ASSERT(p, MA_OWNED); 362 sig = ksi->ksi_signo; 363 psp = p->p_sigacts; 364 mtx_assert(&psp->ps_mtx, MA_OWNED); 365 tf = td->td_frame; 366 onstack = sigonstack(tf->tf_x[13]); 367 368 CTR4(KTR_SIG, "sendsig: td=%p (%s) catcher=%p sig=%d", td, p->p_comm, 369 catcher, sig); 370 371 /* Allocate and validate space for the signal handler context. */ 372 if ((td->td_pflags & TDP_ALTSTACK) != 0 && !(onstack) && 373 SIGISMEMBER(psp->ps_sigonstack, sig)) { 374 fp = (struct sigframe32 *)((uintptr_t)td->td_sigstk.ss_sp + 375 td->td_sigstk.ss_size); 376 #if defined(COMPAT_43) 377 td->td_sigstk.ss_flags |= SS_ONSTACK; 378 #endif 379 } else 380 fp = (struct sigframe32 *)td->td_frame->tf_x[13]; 381 382 /* make room on the stack */ 383 fp--; 384 385 /* make the stack aligned */ 386 fp = (struct sigframe32 *)((unsigned long)(fp) &~ (8 - 1)); 387 /* Populate the siginfo frame. */ 388 get_mcontext32(td, &frame.sf_uc.uc_mcontext, 0); 389 #ifdef VFP 390 get_fpcontext32(td, &frame.sf_vfp); 391 frame.sf_uc.uc_mcontext.mc_vfp_size = sizeof(fp->sf_vfp); 392 frame.sf_uc.uc_mcontext.mc_vfp_ptr = (uint32_t)(uintptr_t)&fp->sf_vfp; 393 #else 394 frame.sf_uc.uc_mcontext.mc_vfp_size = 0; 395 frame.sf_uc.uc_mcontext.mc_vfp_ptr = (uint32_t)NULL; 396 #endif 397 frame.sf_si = siginfo; 398 frame.sf_uc.uc_sigmask = *mask; 399 frame.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK ) 400 ? ((onstack) ? SS_ONSTACK : 0) : SS_DISABLE; 401 frame.sf_uc.uc_stack.ss_sp = (uintptr_t)td->td_sigstk.ss_sp; 402 frame.sf_uc.uc_stack.ss_size = td->td_sigstk.ss_size; 403 404 mtx_unlock(&psp->ps_mtx); 405 PROC_UNLOCK(td->td_proc); 406 407 /* Copy the sigframe out to the user's stack. */ 408 if (copyout(&frame, fp, sizeof(*fp)) != 0) { 409 /* Process has trashed its stack. Kill it. */ 410 CTR2(KTR_SIG, "sendsig: sigexit td=%p fp=%p", td, fp); 411 PROC_LOCK(p); 412 sigexit(td, SIGILL); 413 } 414 415 /* 416 * Build context to run handler in. We invoke the handler 417 * directly, only returning via the trampoline. Note the 418 * trampoline version numbers are coordinated with machine- 419 * dependent code in libc. 420 */ 421 422 tf->tf_x[0] = sig; 423 tf->tf_x[1] = (register_t)&fp->sf_si; 424 tf->tf_x[2] = (register_t)&fp->sf_uc; 425 426 /* the trampoline uses r5 as the uc address */ 427 tf->tf_x[5] = (register_t)&fp->sf_uc; 428 tf->tf_elr = (register_t)catcher; 429 tf->tf_x[13] = (register_t)fp; 430 sysent = p->p_sysent; 431 if (PROC_HAS_SHP(p)) 432 tf->tf_x[14] = (register_t)PROC_SIGCODE(p); 433 else 434 tf->tf_x[14] = (register_t)(PROC_PS_STRINGS(p) - 435 *(sysent->sv_szsigcode)); 436 /* Set the mode to enter in the signal handler */ 437 if ((register_t)catcher & 1) 438 tf->tf_spsr |= PSR_T; 439 else 440 tf->tf_spsr &= ~PSR_T; 441 442 /* Clear the single step flag while in the signal handler */ 443 if ((td->td_pcb->pcb_flags & PCB_SINGLE_STEP) != 0) { 444 td->td_pcb->pcb_flags &= ~PCB_SINGLE_STEP; 445 WRITE_SPECIALREG(mdscr_el1, 446 READ_SPECIALREG(mdscr_el1) & ~MDSCR_SS); 447 isb(); 448 } 449 450 CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_x[14], 451 tf->tf_x[13]); 452 453 PROC_LOCK(p); 454 mtx_lock(&psp->ps_mtx); 455 456 } 457 458 #ifdef COMPAT_43 459 /* 460 * Mirror the osigreturn definition in kern_sig.c for !i386 platforms. This 461 * mirrors what's connected to the FreeBSD/arm syscall. 462 */ 463 int 464 ofreebsd32_sigreturn(struct thread *td, struct ofreebsd32_sigreturn_args *uap) 465 { 466 467 return (nosys(td, (struct nosys_args *)uap)); 468 } 469 #endif 470