xref: /netbsd/sys/arch/mips/mips/netbsd32_machdep.c (revision 6550d01e)
1 /*	$NetBSD: netbsd32_machdep.c,v 1.4 2011/01/14 02:06:28 rmind 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.4 2011/01/14 02:06:28 rmind Exp $");
34 
35 #include "opt_compat_netbsd.h"
36 #include "opt_sa.h"
37 #include "opt_coredump.h"
38 
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/ioctl.h>
42 #include <sys/exec.h>
43 #include <sys/cpu.h>
44 #include <sys/core.h>
45 #include <sys/file.h>
46 #include <sys/time.h>
47 #include <sys/proc.h>
48 #include <sys/uio.h>
49 #include <sys/kernel.h>
50 #include <sys/buf.h>
51 #include <sys/signal.h>
52 #include <sys/signalvar.h>
53 #include <sys/mount.h>
54 #include <sys/syscallargs.h>
55 
56 #include <compat/netbsd32/netbsd32.h>
57 #include <compat/netbsd32/netbsd32_exec.h>
58 #include <compat/netbsd32/netbsd32_syscallargs.h>
59 
60 #include <mips/cache.h>
61 #include <mips/sysarch.h>
62 #include <mips/cachectl.h>
63 #include <mips/locore.h>
64 #include <mips/frame.h>
65 #include <mips/regnum.h>
66 #include <mips/pcb.h>
67 
68 #include <uvm/uvm_extern.h>
69 
70 char machine32[] = MACHINE;
71 char machine_arch32[] = MACHINE32_ARCH;
72 
73 #if 0
74 cpu_coredump32
75 netbsd32_cpu_upcall
76 netbsd32_vm_default_addr
77 #endif
78 
79 int
80 netbsd32_sysarch(struct lwp *l, const struct netbsd32_sysarch_args *uap,
81 	register_t *retval)
82 {
83 	/* {
84 		syscallarg(int) op;
85 		syscallarg(netbsd32_voidp) parms;
86 	} */
87 	struct proc *p = l->l_proc;
88 	void *parms = SCARG_P32(uap, parms);
89 	int error = 0;
90 
91 	switch(SCARG(uap, op)) {
92 	case MIPS_CACHEFLUSH: {
93 		struct mips_cacheflush_args32 cfua;
94 
95 		error = copyin(parms, &cfua, sizeof(cfua));
96 		if (error != 0)
97 			return (error);
98 		error =  mips_user_cacheflush(p, cfua.va, cfua.nbytes,
99 		     cfua.whichcache);
100 		break;
101 	}
102 	case MIPS_CACHECTL: {
103 		struct mips_cachectl_args32 ccua;
104 
105 		error = copyin(parms, &ccua, sizeof(ccua));
106 		if (error != 0)
107 			return (error);
108 		error = mips_user_cachectl(p, ccua.va, ccua.nbytes, ccua.ctl);
109 		break;
110 	}
111 	default:
112 		error = ENOSYS;
113 		break;
114 	}
115 	return (error);
116 }
117 
118 #ifdef COMPAT_13
119 int
120 compat_13_netbsd32_sigreturn(struct lwp *l,
121 	const struct compat_13_netbsd32_sigreturn_args *uap,
122 	register_t *retval)
123 {
124 	struct compat_13_sys_sigreturn_args ua;
125 
126 	NETBSD32TOP_UAP(sigcntxp, struct sigcontext13 *);
127 
128 	return compat_13_sys_sigreturn(l, &ua, retval);
129 }
130 #endif
131 
132 #ifdef COMPAT_16
133 int
134 compat_16_netbsd32___sigreturn14(struct lwp *l,
135 	const struct compat_16_netbsd32___sigreturn14_args *uap,
136 	register_t *retval)
137 {
138 	struct compat_16_sys___sigreturn14_args ua;
139 
140 	NETBSD32TOP_UAP(sigcntxp, struct sigcontext *);
141 
142 	return compat_16_sys___sigreturn14(l, &ua, retval);
143 }
144 #endif
145 
146 vaddr_t
147 netbsd32_vm_default_addr(struct proc *p, vaddr_t base, vsize_t size)
148 {
149 	return VM_DEFAULT_ADDRESS32(base, size);
150 }
151 
152 
153 struct sigframe_siginfo32 {
154 	siginfo32_t sf_si;
155 	ucontext32_t sf_uc;
156 };
157 
158 /*
159  * Send a signal to process.
160  */
161 static void
162 netbsd32_sendsig_siginfo(const ksiginfo_t *ksi, const sigset_t *mask)
163 {
164 	struct lwp * const l = curlwp;
165 	struct proc * const p = l->l_proc;
166 	struct sigacts * const ps = p->p_sigacts;
167 	int onstack, error;
168 	int sig = ksi->ksi_signo;
169 	struct sigframe_siginfo32 *sfp = getframe(l, sig, &onstack);
170 	struct sigframe_siginfo32 sf;
171 	struct frame * const tf = l->l_md.md_regs;
172 	size_t sfsz;
173 	sig_t catcher = SIGACTION(p, sig).sa_handler;
174 
175 	sfp--;
176 
177 	netbsd32_si_to_si32(&sf.sf_si, (const siginfo_t *)&ksi->ksi_info);
178 
179         /* Build stack frame for signal trampoline. */
180         switch (ps->sa_sigdesc[sig].sd_vers) {
181         case 0:         /* handled by sendsig_sigcontext */
182         case 1:         /* handled by sendsig_sigcontext */
183         default:        /* unknown version */
184                 printf("sendsig_siginfo: bad version %d\n",
185                     ps->sa_sigdesc[sig].sd_vers);
186                 sigexit(l, SIGILL);
187         case 2:
188                 break;
189         }
190 
191 	sf.sf_uc.uc_flags = _UC_SIGMASK
192 	    | ((l->l_sigstk.ss_flags & SS_ONSTACK)
193 	    ? _UC_SETSTACK : _UC_CLRSTACK);
194 	sf.sf_uc.uc_sigmask = *mask;
195 	sf.sf_uc.uc_link = (intptr_t)l->l_ctxlink;
196 	memset(&sf.sf_uc.uc_stack, 0, sizeof(sf.sf_uc.uc_stack));
197 	sfsz = offsetof(struct sigframe_siginfo32, sf_uc.uc_mcontext);
198 	if (p->p_md.md_abi == _MIPS_BSD_API_O32)
199 		sfsz += sizeof(mcontext_o32_t);
200 	else
201 		sfsz += sizeof(mcontext32_t);
202 	sendsig_reset(l, sig);
203 	mutex_exit(p->p_lock);
204 	cpu_getmcontext32(l, &sf.sf_uc.uc_mcontext, &sf.sf_uc.uc_flags);
205 	error = copyout(&sf, sfp, sfsz);
206 	mutex_enter(p->p_lock);
207 
208 	if (error != 0) {
209 		/*
210 		 * Process has trashed its stack; give it an illegal
211 		 * instruction to halt it in its tracks.
212 		 */
213 		sigexit(l, SIGILL);
214 		/* NOTREACHED */
215 	}
216 
217 	/*
218 	 * Set up the registers to directly invoke the signal
219 	 * handler.  The return address will be set up to point
220 	 * to the signal trampoline to bounce us back.
221 	 */
222 	tf->f_regs[_R_A0] = sig;
223 	tf->f_regs[_R_A1] = (intptr_t)&sfp->sf_si;
224 	tf->f_regs[_R_A2] = (intptr_t)&sfp->sf_uc;
225 
226 	tf->f_regs[_R_PC] = (intptr_t)catcher;
227 	tf->f_regs[_R_T9] = (intptr_t)catcher;
228 	tf->f_regs[_R_SP] = (intptr_t)sfp;
229 	tf->f_regs[_R_RA] = (intptr_t)ps->sa_sigdesc[sig].sd_tramp;
230 
231 	/* Remember that we're now on the signal stack. */
232 	if (onstack)
233 		l->l_sigstk.ss_flags |= SS_ONSTACK;
234 }
235 
236 void
237 netbsd32_sendsig(const ksiginfo_t *ksi, const sigset_t *mask)
238 {
239 #ifdef COMPAT_16
240 	if (curproc->p_sigacts->sa_sigdesc[ksi->ksi_signo].sd_vers < 2)
241 		sendsig_sigcontext(ksi, mask);
242 	else
243 #endif
244 		netbsd32_sendsig_siginfo(ksi, mask);
245 }
246 
247 void
248 cpu_getmcontext32(struct lwp *l, mcontext32_t *mc32, unsigned int *flagsp)
249 {
250 	mcontext_o32_t * const mco32 = (mcontext_o32_t *)mc32;
251 	mcontext_t mc;
252 	size_t i;
253 
254 	if (l->l_proc->p_md.md_abi == _MIPS_BSD_API_N32) {
255 		cpu_getmcontext(l, (mcontext_t *)mc32, flagsp);
256 		return;
257 	}
258 
259 	cpu_getmcontext(l, &mc, flagsp);
260 	for (i = 0; i < __arraycount(mc.__gregs); i++)
261 		mco32->__gregs[i] = mc.__gregs[i];
262 	if (*flagsp & _UC_FPU)
263 		memcpy(&mco32->__fpregs, &mc.__fpregs,
264 		    sizeof(struct fpreg_oabi));
265 }
266 
267 int
268 cpu_setmcontext32(struct lwp *l, const mcontext32_t *mc32, unsigned int flags)
269 {
270 	const mcontext_o32_t * const mco32 = (const mcontext_o32_t *)mc32;
271 	mcontext_t mc;
272 	size_t i;
273 
274 	if (l->l_proc->p_md.md_abi == _MIPS_BSD_API_N32)
275 		return cpu_setmcontext(l, (const mcontext_t *)mc32, flags);
276 
277 	for (i = 0; i < __arraycount(mc.__gregs); i++)
278 		mc.__gregs[i] = mco32->__gregs[i];
279 	if (flags & _UC_FPU)
280 		memcpy(&mc.__fpregs, &mco32->__fpregs,
281 		    sizeof(struct fpreg_oabi));
282 	return cpu_setmcontext(l, &mc, flags);
283 }
284 
285 #ifdef COREDUMP
286 /*
287  * Dump the machine specific segment at the start of a core dump.
288  */
289 int
290 cpu_coredump32(struct lwp *l, void *iocookie, struct core32 *chdr)
291 {
292 	int error;
293 	struct coreseg cseg;
294 	struct cpustate {
295 		struct frame frame;
296 		struct fpreg fpregs;
297 	} cpustate;
298 
299 	if (iocookie == NULL) {
300 		CORE_SETMAGIC(*chdr, COREMAGIC, MID_MACHINE, 0);
301 		chdr->c_hdrsize = ALIGN(sizeof(struct core));
302 		chdr->c_seghdrsize = ALIGN(sizeof(struct coreseg));
303 		chdr->c_cpusize = sizeof(struct cpustate);
304 		chdr->c_nseg++;
305 		return 0;
306 	}
307 
308 	if ((l->l_md.md_flags & MDP_FPUSED) && l == fpcurlwp)
309 		savefpregs(l);
310 
311 	struct pcb * const pcb = lwp_getpcb(l);
312 	cpustate.frame = *l->l_md.md_regs;
313 	cpustate.fpregs = pcb->pcb_fpregs;
314 
315 	CORE_SETMAGIC(cseg, CORESEGMAGIC, MID_MACHINE, CORE_CPU);
316 	cseg.c_addr = 0;
317 	cseg.c_size = chdr->c_cpusize;
318 
319 	error = coredump_write(iocookie, UIO_SYSSPACE, &cseg,
320 	    chdr->c_seghdrsize);
321 	if (error)
322 		return error;
323 
324 	return coredump_write(iocookie, UIO_SYSSPACE, &cpustate,
325 	    chdr->c_cpusize);
326 }
327 #endif
328