1 /* $NetBSD: linux_machdep.c,v 1.4 2024/02/07 04:20:28 msaitoh Exp $ */ 2 3 /*- 4 * Copyright (c) 2021 Ryo Shimizu 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 17 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: linux_machdep.c,v 1.4 2024/02/07 04:20:28 msaitoh Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/proc.h> 35 #include <sys/exec.h> 36 #include <sys/syscallargs.h> 37 38 #include <compat/linux/common/linux_types.h> 39 #include <compat/linux/common/linux_signal.h> 40 #include <compat/linux/common/linux_errno.h> 41 #include <compat/linux/common/linux_exec.h> 42 #include <compat/linux/common/linux_ioctl.h> 43 #include <compat/linux/common/linux_prctl.h> 44 #include <compat/linux/common/linux_machdep.h> 45 #include <compat/linux/common/linux_ipc.h> 46 #include <compat/linux/common/linux_sem.h> 47 #include <compat/linux/linux_syscall.h> 48 #include <compat/linux/linux_syscallargs.h> 49 50 void 51 linux_setregs(struct lwp *l, struct exec_package *epp, vaddr_t stack) 52 { 53 setregs(l, epp, stack); 54 } 55 56 static void 57 linux_save_sigcontext(struct lwp *l, struct linux_sigcontext *ctx) 58 { 59 ucontext_t uc; 60 61 cpu_getmcontext(l, &uc.uc_mcontext, &uc.uc_flags); 62 63 memset(ctx, 0, sizeof(*ctx)); 64 /* ctx->fault_address = 0; */ 65 CTASSERT(sizeof(ctx->regs) <= sizeof(uc.uc_mcontext.__gregs)); 66 for (int i = 0; i < __arraycount(ctx->regs); i++) 67 ctx->regs[i] = uc.uc_mcontext.__gregs[i]; 68 ctx->sp = uc.uc_mcontext.__gregs[_REG_SP]; 69 ctx->pc = uc.uc_mcontext.__gregs[_REG_PC]; 70 ctx->pstate = uc.uc_mcontext.__gregs[_REG_SPSR]; 71 72 if (uc.uc_flags & _UC_FPU) { 73 struct fpsimd_context *fpsimd; 74 75 fpsimd = (struct fpsimd_context *)ctx->__reserved; 76 fpsimd->head.magic = FPSIMD_MAGIC; 77 fpsimd->head.size = sizeof(struct fpsimd_context); 78 fpsimd->fpsr = uc.uc_mcontext.__fregs.__fpsr; 79 fpsimd->fpcr = uc.uc_mcontext.__fregs.__fpcr; 80 CTASSERT(sizeof(fpsimd->vregs) == 81 sizeof(uc.uc_mcontext.__fregs.__qregs)); 82 memcpy(fpsimd->vregs, uc.uc_mcontext.__fregs.__qregs, 83 sizeof(uc.uc_mcontext.__fregs.__qregs)); 84 } 85 86 /* ctx->__reserved[] has already been terminated by memset() */ 87 } 88 89 static void 90 aarch64_linux_to_native_ucontext(ucontext_t *uc, struct linux_ucontext *luc) 91 { 92 struct linux_sigcontext *ctx = &luc->luc_mcontext; 93 struct fpsimd_context *fpsimd; 94 95 memset(uc, 0, sizeof(*uc)); 96 97 /* build .uc_flags, .uc_link, and .uc_sigmask */ 98 uc->uc_flags = (_UC_SIGMASK | _UC_CPU | _UC_STACK | _UC_CLRSTACK); 99 uc->uc_link = NULL; 100 linux_to_native_sigset(&uc->uc_sigmask, &luc->luc_sigmask); 101 102 /* build .uc_stack */ 103 if (luc->luc_stack.ss_flags & LINUX_SS_ONSTACK) 104 uc->uc_stack.ss_flags |= SS_ONSTACK; 105 if (luc->luc_stack.ss_flags & LINUX_SS_DISABLE) 106 uc->uc_stack.ss_flags |= SS_DISABLE; 107 uc->uc_stack.ss_sp = luc->luc_stack.ss_sp; 108 uc->uc_stack.ss_size = luc->luc_stack.ss_size; 109 110 /* build .uc_mcontext */ 111 CTASSERT(sizeof(ctx->regs) <= sizeof(uc->uc_mcontext.__gregs)); 112 for (int i = 0; i < __arraycount(ctx->regs); i++) 113 uc->uc_mcontext.__gregs[i] = ctx->regs[i]; 114 uc->uc_mcontext.__gregs[_REG_SP] = ctx->sp; 115 uc->uc_mcontext.__gregs[_REG_PC] = ctx->pc; 116 uc->uc_mcontext.__gregs[_REG_SPSR] = ctx->pstate; 117 118 fpsimd = (struct fpsimd_context *)ctx->__reserved; 119 if (fpsimd->head.magic == FPSIMD_MAGIC) { 120 uc->uc_flags |= _UC_FPU; 121 uc->uc_mcontext.__fregs.__fpsr = fpsimd->fpsr; 122 uc->uc_mcontext.__fregs.__fpcr = fpsimd->fpcr; 123 CTASSERT(sizeof(fpsimd->vregs) == 124 sizeof(uc->uc_mcontext.__fregs.__qregs)); 125 memcpy(uc->uc_mcontext.__fregs.__qregs, fpsimd->vregs, 126 sizeof(uc->uc_mcontext.__fregs.__qregs)); 127 } 128 } 129 130 void 131 linux_sendsig(const ksiginfo_t *ksi, const sigset_t *mask) 132 { 133 struct lwp * const l = curlwp; 134 struct proc * const p = l->l_proc; 135 struct trapframe * const tf = lwp_trapframe(l); 136 stack_t * const ss = &l->l_sigstk; 137 const int sig = ksi->ksi_signo; 138 const sig_t handler = SIGACTION(p, sig).sa_handler; 139 struct linux_rt_sigframe *u_sigframe, *tmp_sigframe; 140 vaddr_t sp; 141 int error; 142 const bool onstack_p = /* use signal stack? */ 143 (ss->ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 && 144 (SIGACTION(p, sig).sa_flags & SA_ONSTACK) != 0; 145 146 sp = onstack_p ? ((vaddr_t)ss->ss_sp + ss->ss_size) & -16 : tf->tf_sp; 147 148 /* allocate sigframe on userstack */ 149 sp -= sizeof(struct linux_rt_sigframe); 150 u_sigframe = (struct linux_rt_sigframe *)sp; 151 152 /* build linux sigframe, and copyout to user stack */ 153 tmp_sigframe = kmem_zalloc(sizeof(*tmp_sigframe), KM_SLEEP); 154 tmp_sigframe->uc.luc_flags = 0; 155 tmp_sigframe->uc.luc_link = NULL; 156 tmp_sigframe->uc.luc_stack.ss_sp = ss->ss_sp; 157 tmp_sigframe->uc.luc_stack.ss_size = ss->ss_size; 158 tmp_sigframe->uc.luc_stack.ss_flags = 0; 159 if (ss->ss_flags & SS_ONSTACK) 160 tmp_sigframe->uc.luc_stack.ss_flags |= LINUX_SS_ONSTACK; 161 if (ss->ss_flags & SS_DISABLE) 162 tmp_sigframe->uc.luc_stack.ss_flags |= LINUX_SS_DISABLE; 163 native_to_linux_sigset(&tmp_sigframe->uc.luc_sigmask, mask); 164 native_to_linux_siginfo(&tmp_sigframe->info, &ksi->ksi_info); 165 sendsig_reset(l, sig); 166 167 mutex_exit(p->p_lock); 168 linux_save_sigcontext(l, &tmp_sigframe->uc.luc_mcontext); 169 170 /* copy linux sigframe onto the user stack */ 171 error = copyout(tmp_sigframe, u_sigframe, sizeof(*tmp_sigframe)); 172 kmem_free(tmp_sigframe, sizeof(*tmp_sigframe)); 173 174 mutex_enter(p->p_lock); 175 176 if (error != 0 || (vaddr_t)handler >= VM_MAXUSER_ADDRESS) { 177 sigexit(l, SIGILL); 178 return; 179 } 180 181 /* build context to run handler in. */ 182 tf->tf_reg[0] = native_to_linux_signo[sig]; 183 tf->tf_reg[1] = (uint64_t)&u_sigframe->info; 184 tf->tf_reg[2] = (uint64_t)&u_sigframe->uc; 185 tf->tf_pc = (uint64_t)handler; 186 tf->tf_sp = sp; 187 188 /* sigreturn trampoline */ 189 extern char linux_sigcode[], linux_rt_sigcode[]; 190 vsize_t linux_rt_sigcode_offset = linux_rt_sigcode - linux_sigcode; 191 tf->tf_lr = (uint64_t)p->p_sigctx.ps_sigcode + linux_rt_sigcode_offset; 192 193 if (onstack_p) 194 ss->ss_flags |= SS_ONSTACK; 195 } 196 197 int 198 linux_sys_rt_sigreturn(struct lwp *l, const void *v, register_t *retval) 199 { 200 struct trapframe * const tf = lwp_trapframe(l); 201 struct proc * const p = l->l_proc; 202 struct linux_rt_sigframe *lsigframe; 203 ucontext_t uc; 204 int error; 205 206 /* 207 * struct linux_rt_sigframe is variable size, 208 * but netbsd/aarch64's linux_sendsig() always pushes a full size 209 * linux_rt_sigframe. 210 */ 211 lsigframe = kmem_zalloc(sizeof(*lsigframe), KM_SLEEP); 212 error = copyin((void *)tf->tf_sp, lsigframe, sizeof(*lsigframe)); 213 if (error != 0) 214 goto done; 215 216 aarch64_linux_to_native_ucontext(&uc, &lsigframe->uc); 217 218 mutex_enter(p->p_lock); 219 error = setucontext(l, &uc); 220 mutex_exit(p->p_lock); 221 if (error != 0) 222 goto done; 223 error = EJUSTRETURN; 224 225 done: 226 kmem_free(lsigframe, sizeof(*lsigframe)); 227 return error; 228 } 229 230 void 231 linux_trapsignal(struct lwp *l, ksiginfo_t *ksi) 232 { 233 /* 234 * XXX: TODO 235 * should be convert siginfo from native to linux 236 */ 237 trapsignal(l, ksi); 238 } 239 240 int 241 linux_usertrap(struct lwp *l, vaddr_t trapaddr, void *arg) 242 { 243 /* not used */ 244 return 0; 245 } 246 247 dev_t 248 linux_fakedev(dev_t dev, int raw) 249 { 250 /* TODO if needed */ 251 return dev; 252 } 253 254 int 255 linux_machdepioctl(struct lwp *l, const struct linux_sys_ioctl_args *uap, 256 register_t *retval) 257 { 258 /* TODO if needed */ 259 return EINVAL; 260 } 261