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