1 /* $NetBSD: netbsd32_machdep.c,v 1.23 2021/11/06 20:42:56 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 2009 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Matt Thomas <matt@3am-software.com>.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: netbsd32_machdep.c,v 1.23 2021/11/06 20:42:56 thorpej Exp $");
34
35 #include "opt_compat_netbsd.h"
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/ioctl.h>
40 #include <sys/exec.h>
41 #include <sys/cpu.h>
42 #include <sys/core.h>
43 #include <sys/file.h>
44 #include <sys/time.h>
45 #include <sys/proc.h>
46 #include <sys/uio.h>
47 #include <sys/kernel.h>
48 #include <sys/buf.h>
49 #include <sys/signal.h>
50 #include <sys/signalvar.h>
51 #include <sys/mount.h>
52 #include <sys/syscallargs.h>
53 #include <sys/compat_stub.h>
54
55 #include <compat/netbsd32/netbsd32.h>
56 #include <compat/netbsd32/netbsd32_exec.h>
57 #include <compat/netbsd32/netbsd32_syscallargs.h>
58
59 #include <mips/cache.h>
60 #include <mips/sysarch.h>
61 #include <mips/cachectl.h>
62 #include <mips/locore.h>
63 #include <mips/frame.h>
64 #include <mips/regnum.h>
65 #include <mips/pcb.h>
66
67 #include <uvm/uvm_extern.h>
68
69 const char machine32[] = MACHINE;
70 const char machine_archo32[] = MACHINE32_OARCH;
71 #ifdef MACHINE32_NARCH
72 const char machine_archn32[] = MACHINE32_NARCH;
73 #endif
74
75 #if 0
76 cpu_coredump32
77 netbsd32_cpu_upcall
78 netbsd32_vm_default_addr
79 #endif
80
81 struct sigframe_siginfo32 {
82 siginfo32_t sf_si;
83 ucontext32_t sf_uc;
84 };
85
86 /*
87 * Send a signal to process.
88 */
89 void
netbsd32_sendsig_siginfo(const ksiginfo_t * ksi,const sigset_t * mask)90 netbsd32_sendsig_siginfo(const ksiginfo_t *ksi, const sigset_t *mask)
91 {
92 struct lwp * const l = curlwp;
93 struct proc * const p = l->l_proc;
94 struct sigacts * const ps = p->p_sigacts;
95 int onstack, error;
96 int sig = ksi->ksi_signo;
97 struct sigframe_siginfo32 *sfp = getframe(l, sig, &onstack);
98 struct sigframe_siginfo32 sf;
99 struct trapframe * const tf = l->l_md.md_utf;
100 size_t sfsz;
101 sig_t catcher = SIGACTION(p, sig).sa_handler;
102
103 sfp--;
104
105 memset(&sf, 0, sizeof(sf));
106 netbsd32_si_to_si32(&sf.sf_si, (const siginfo_t *)&ksi->ksi_info);
107
108 /* Build stack frame for signal trampoline. */
109 switch (ps->sa_sigdesc[sig].sd_vers) {
110 case __SIGTRAMP_SIGCODE_VERSION: /* handled by sendsig_sigcontext */
111 case __SIGTRAMP_SIGCONTEXT_VERSION: /* handled by sendsig_sigcontext */
112 default: /* unknown version */
113 printf("%s: bad version %d\n", __func__,
114 ps->sa_sigdesc[sig].sd_vers);
115 sigexit(l, SIGILL);
116 case __SIGTRAMP_SIGINFO_VERSION:
117 break;
118 }
119
120 sf.sf_uc.uc_flags = _UC_SIGMASK
121 | ((l->l_sigstk.ss_flags & SS_ONSTACK)
122 ? _UC_SETSTACK : _UC_CLRSTACK);
123 sf.sf_uc.uc_sigmask = *mask;
124 sf.sf_uc.uc_link = (intptr_t)l->l_ctxlink;
125 sfsz = offsetof(struct sigframe_siginfo32, sf_uc.uc_mcontext);
126 if (p->p_md.md_abi == _MIPS_BSD_API_O32)
127 sfsz += sizeof(mcontext_o32_t);
128 else
129 sfsz += sizeof(mcontext32_t);
130 sendsig_reset(l, sig);
131 mutex_exit(p->p_lock);
132 cpu_getmcontext32(l, &sf.sf_uc.uc_mcontext, &sf.sf_uc.uc_flags);
133 error = copyout(&sf, sfp, sfsz);
134 mutex_enter(p->p_lock);
135 if (error != 0) {
136 /*
137 * Process has trashed its stack; give it an illegal
138 * instruction to halt it in its tracks.
139 */
140 sigexit(l, SIGILL);
141 /* NOTREACHED */
142 }
143
144 /*
145 * Set up the registers to directly invoke the signal
146 * handler. The return address will be set up to point
147 * to the signal trampoline to bounce us back.
148 */
149 tf->tf_regs[_R_A0] = sig;
150 tf->tf_regs[_R_A1] = (intptr_t)&sfp->sf_si;
151 tf->tf_regs[_R_A2] = (intptr_t)&sfp->sf_uc;
152
153 tf->tf_regs[_R_PC] = (intptr_t)catcher;
154 tf->tf_regs[_R_T9] = (intptr_t)catcher;
155 tf->tf_regs[_R_SP] = (intptr_t)sfp;
156 tf->tf_regs[_R_RA] = (intptr_t)ps->sa_sigdesc[sig].sd_tramp;
157
158 /* Remember that we're now on the signal stack. */
159 if (onstack)
160 l->l_sigstk.ss_flags |= SS_ONSTACK;
161 }
162
163 int
netbsd32_sysarch(struct lwp * l,const struct netbsd32_sysarch_args * uap,register_t * retval)164 netbsd32_sysarch(struct lwp *l, const struct netbsd32_sysarch_args *uap,
165 register_t *retval)
166 {
167 /* {
168 syscallarg(int) op;
169 syscallarg(netbsd32_voidp) parms;
170 } */
171 struct proc *p = l->l_proc;
172 void *parms = SCARG_P32(uap, parms);
173 int error = 0;
174
175 switch(SCARG(uap, op)) {
176 case MIPS_CACHEFLUSH: {
177 struct mips_cacheflush_args32 cfua;
178
179 error = copyin(parms, &cfua, sizeof(cfua));
180 if (error != 0)
181 return (error);
182 error = mips_user_cacheflush(p, cfua.va, cfua.nbytes,
183 cfua.whichcache);
184 break;
185 }
186 case MIPS_CACHECTL: {
187 struct mips_cachectl_args32 ccua;
188
189 error = copyin(parms, &ccua, sizeof(ccua));
190 if (error != 0)
191 return (error);
192 error = mips_user_cachectl(p, ccua.va, ccua.nbytes, ccua.ctl);
193 break;
194 }
195 default:
196 error = ENOSYS;
197 break;
198 }
199 return (error);
200 }
201
202 vaddr_t
netbsd32_vm_default_addr(struct proc * p,vaddr_t base,vsize_t size,int topdown)203 netbsd32_vm_default_addr(struct proc *p, vaddr_t base, vsize_t size,
204 int topdown)
205 {
206 if (topdown)
207 return VM_DEFAULT_ADDRESS32_TOPDOWN(base, size);
208 else
209 return VM_DEFAULT_ADDRESS32_BOTTOMUP(base, size);
210 }
211
212 void
cpu_getmcontext32(struct lwp * l,mcontext32_t * mc32,unsigned int * flagsp)213 cpu_getmcontext32(struct lwp *l, mcontext32_t *mc32, unsigned int *flagsp)
214 {
215 mcontext_o32_t * const mco32 = (mcontext_o32_t *)mc32;
216 mcontext_t mc;
217 size_t i;
218
219 if (l->l_proc->p_md.md_abi == _MIPS_BSD_API_N32) {
220 cpu_getmcontext(l, (mcontext_t *)mc32, flagsp);
221 return;
222 }
223
224 cpu_getmcontext(l, &mc, flagsp);
225 for (i = 1; i < __arraycount(mc.__gregs); i++)
226 mco32->__gregs[i] = mc.__gregs[i];
227 if (*flagsp & _UC_FPU)
228 memcpy(&mco32->__fpregs, &mc.__fpregs,
229 sizeof(struct fpreg_oabi));
230 mco32->_mc_tlsbase = mc._mc_tlsbase;
231 *flagsp |= _UC_TLSBASE;
232 }
233
234 int
cpu_mcontext32_validate(struct lwp * l,const mcontext32_t * mc32)235 cpu_mcontext32_validate(struct lwp *l, const mcontext32_t *mc32)
236 {
237 return 0;
238 }
239
240 int
cpu_setmcontext32(struct lwp * l,const mcontext32_t * mc32,unsigned int flags)241 cpu_setmcontext32(struct lwp *l, const mcontext32_t *mc32, unsigned int flags)
242 {
243 const mcontext_o32_t * const mco32 = (const mcontext_o32_t *)mc32;
244 mcontext_t mc;
245 size_t i, error;
246
247 if (flags & _UC_CPU) {
248 error = cpu_mcontext32_validate(l, mc32);
249 if (error)
250 return error;
251 }
252
253 if (l->l_proc->p_md.md_abi == _MIPS_BSD_API_N32)
254 return cpu_setmcontext(l, (const mcontext_t *)mc32, flags);
255
256 for (i = 0; i < __arraycount(mc.__gregs); i++)
257 mc.__gregs[i] = mco32->__gregs[i];
258 if (flags & _UC_FPU)
259 memcpy(&mc.__fpregs, &mco32->__fpregs,
260 sizeof(struct fpreg_oabi));
261 mc._mc_tlsbase = mco32->_mc_tlsbase;
262 return cpu_setmcontext(l, &mc, flags);
263 }
264
265 /*
266 * Dump the machine specific segment at the start of a core dump.
267 */
268 int
cpu_coredump32(struct lwp * l,struct coredump_iostate * iocookie,struct core32 * chdr)269 cpu_coredump32(struct lwp *l, struct coredump_iostate *iocookie,
270 struct core32 *chdr)
271 {
272 int error;
273 struct coreseg cseg;
274 struct cpustate {
275 struct trapframe frame;
276 struct fpreg fpregs;
277 } cpustate;
278
279 if (iocookie == NULL) {
280 CORE_SETMAGIC(*chdr, COREMAGIC, MID_MACHINE, 0);
281 chdr->c_hdrsize = ALIGN(sizeof(struct core));
282 chdr->c_seghdrsize = ALIGN(sizeof(struct coreseg));
283 chdr->c_cpusize = sizeof(struct cpustate);
284 chdr->c_nseg++;
285 return 0;
286 }
287
288 fpu_save(l);
289
290 struct pcb * const pcb = lwp_getpcb(l);
291 cpustate.frame = *l->l_md.md_utf;
292 cpustate.fpregs = pcb->pcb_fpregs;
293
294 CORE_SETMAGIC(cseg, CORESEGMAGIC, MID_MACHINE, CORE_CPU);
295 cseg.c_addr = 0;
296 cseg.c_size = chdr->c_cpusize;
297
298 MODULE_HOOK_CALL(coredump_write_hook, (iocookie, UIO_SYSSPACE, &cseg,
299 chdr->c_seghdrsize), ENOSYS, error);
300 if (error)
301 return error;
302
303 MODULE_HOOK_CALL(coredump_write_hook, (iocookie, UIO_SYSSPACE,
304 &cpustate, chdr->c_cpusize), ENOSYS, error);
305
306 return error;
307 }
308
309 static const char *
netbsd32_machine32(void)310 netbsd32_machine32(void)
311 {
312
313 return PROC_MACHINE_ARCH32(curproc);
314 }
315
316 void
netbsd32_machdep_md_init(void)317 netbsd32_machdep_md_init(void)
318 {
319
320 MODULE_HOOK_SET(netbsd32_machine32_hook, netbsd32_machine32);
321 }
322
323 void
netbsd32_machdep_md_fini(void)324 netbsd32_machdep_md_fini(void)
325 {
326
327 MODULE_HOOK_UNSET(netbsd32_machine32_hook);
328 }
329
330
331