xref: /illumos-gate/usr/src/ucblib/libucb/sparc/sys/signal.c (revision dd72704bd9e794056c558153663c739e2012d721)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved	*/
29 
30 /*
31  * Portions of this source code were derived from Berkeley 4.3 BSD
32  * under license from the Regents of the University of California.
33  */
34 
35 /*
36  * 4.3BSD signal compatibility functions
37  *
38  * the implementation interprets signal masks equal to -1 as "all of the
39  * signals in the signal set", thereby allowing signals with numbers
40  * above 32 to be blocked when referenced in code such as:
41  *
42  *	for (i = 0; i < NSIG; i++)
43  *		mask |= sigmask(i)
44  */
45 
46 #include <sys/types.h>
47 #include <ucontext.h>
48 #include <signal.h>
49 #include <errno.h>
50 
51 #undef	BUS_OBJERR	/* namespace conflict */
52 #include <sys/siginfo.h>
53 #include "libc.h"
54 
55 #pragma weak sigvechandler = _sigvechandler
56 #pragma weak sigsetmask = _sigsetmask
57 #pragma weak sigblock = _sigblock
58 #pragma weak sigpause = usigpause
59 #pragma weak sigvec = _sigvec
60 #pragma weak sigstack = _sigstack
61 #pragma weak signal = usignal
62 #pragma weak siginterrupt = _siginterrupt
63 
64 /*
65  * DO NOT remove the _ from these 3 functions or the subsequent
66  * calls to them below.  The non _ versions of these functions
67  * are the wrong functions to call.  This is BCP.  Extra
68  * care should be taken when modifying this code.
69  */
70 extern int _sigfillset(sigset_t *);
71 extern int _sigemptyset(sigset_t *);
72 extern int _sigprocmask(int, const sigset_t *, sigset_t *);
73 
74 #define	set2mask(setp) ((setp)->__sigbits[0])
75 #define	mask2set(mask, setp) \
76 	((mask) == -1 ? _sigfillset(setp) : \
77 	    ((void) _sigemptyset(setp), (((setp)->__sigbits[0]) = (int)(mask))))
78 
79 void (*_siguhandler[NSIG])() = { 0 };
80 
81 /*
82  * forward declarations
83  */
84 int ucbsiginterrupt(int, int);
85 int ucbsigvec(int, struct sigvec *, struct sigvec *);
86 int ucbsigpause(int);
87 int ucbsigblock(int);
88 int ucbsigsetmask(int);
89 static void ucbsigvechandler(int, siginfo_t *, ucontext_t *);
90 
91 /*
92  * sigvechandler is the real signal handler installed for all
93  * signals handled in the 4.3BSD compatibility interface - it translates
94  * SVR4 signal hander arguments into 4.3BSD signal handler arguments
95  * and then calls the real handler
96  */
97 
98 int
99 _sigvechandler(int sig, siginfo_t *sip, ucontext_t *ucp)
100 {
101 	ucbsigvechandler(sig, sip, ucp);
102 	return (0);	/* keep the same as the original prototype */
103 }
104 
105 static void
106 ucbsigvechandler(int sig, siginfo_t *sip, ucontext_t *ucp)
107 {
108 	struct sigcontext sc;
109 	int code;
110 	char *addr;
111 #ifdef NEVER
112 	int gwinswitch = 0;
113 #endif
114 
115 	sc.sc_onstack = ((ucp->uc_stack.ss_flags & SS_ONSTACK) != 0);
116 	sc.sc_mask = set2mask(&ucp->uc_sigmask);
117 
118 #if defined(__sparc)
119 	if (sig == SIGFPE && sip != NULL && SI_FROMKERNEL(sip) &&
120 	    (sip->si_code == FPE_INTDIV || sip->si_code == FPE_INTOVF)) {
121 		/*
122 		 * Hack to emulate the 4.x kernel behavior of incrementing
123 		 * the PC on integer divide by zero and integer overflow
124 		 * on sparc machines.  (5.x does not increment the PC.)
125 		 */
126 		ucp->uc_mcontext.gregs[REG_PC] =
127 		    ucp->uc_mcontext.gregs[REG_nPC];
128 		ucp->uc_mcontext.gregs[REG_nPC] += 4;
129 	}
130 	sc.sc_sp = ucp->uc_mcontext.gregs[REG_SP];
131 	sc.sc_pc = ucp->uc_mcontext.gregs[REG_PC];
132 	sc.sc_npc = ucp->uc_mcontext.gregs[REG_nPC];
133 
134 	/* XX64 There is no REG_PSR for sparcv9, we map in REG_CCR for now */
135 #if defined(__sparcv9)
136 	sc.sc_psr = ucp->uc_mcontext.gregs[REG_CCR];
137 #else
138 	sc.sc_psr = ucp->uc_mcontext.gregs[REG_PSR];
139 #endif
140 
141 	sc.sc_g1 = ucp->uc_mcontext.gregs[REG_G1];
142 	sc.sc_o0 = ucp->uc_mcontext.gregs[REG_O0];
143 
144 	/*
145 	 * XXX - What a kludge!
146 	 * Store a pointer to the original ucontext_t in the sigcontext
147 	 * so that it's available to the sigcleanup call that needs to
148 	 * return from the signal handler.  Otherwise, vital information
149 	 * (e.g., the "out" registers) that's only saved in the
150 	 * ucontext_t isn't available to sigcleanup.
151 	 */
152 	sc.sc_wbcnt = (int)(sizeof (*ucp));
153 	sc.sc_spbuf[0] = (char *)(uintptr_t)sig;
154 	sc.sc_spbuf[1] = (char *)ucp;
155 #ifdef NEVER
156 	/*
157 	 * XXX - Sorry, we can never pass the saved register windows
158 	 * on in the sigcontext because we use that space to save the
159 	 * ucontext_t.
160 	 */
161 	if (ucp->uc_mcontext.gwins != (gwindows_t *)0) {
162 		int i, j;
163 
164 		gwinswitch = 1;
165 		sc.sc_wbcnt = ucp->uc_mcontext.gwins->wbcnt;
166 		/* XXX - should use bcopy to move this in bulk */
167 		for (i = 0; i < ucp->uc_mcontext.gwins; i++) {
168 			sc.sc_spbuf[i] = ucp->uc_mcontext.gwins->spbuf[i];
169 			for (j = 0; j < 8; j++)
170 				sc.sc_wbuf[i][j] =
171 				    ucp->uc_mcontext.gwins->wbuf[i].rw_local[j];
172 			for (j = 0; j < 8; j++)
173 				sc.sc_wbuf[i][j+8] =
174 				    ucp->uc_mcontext.gwins->wbuf[i].rw_in[j];
175 		}
176 	}
177 #endif
178 #endif
179 
180 	/*
181 	 * Translate signal codes from new to old.
182 	 * /usr/include/sys/siginfo.h contains new codes.
183 	 * /usr/ucbinclude/sys/signal.h contains old codes.
184 	 */
185 	code = 0;
186 	addr = SIG_NOADDR;
187 	if (sip != NULL && SI_FROMKERNEL(sip)) {
188 		addr = sip->si_addr;
189 
190 		switch (sig) {
191 		case SIGILL:
192 			switch (sip->si_code) {
193 			case ILL_PRVOPC:
194 				code = ILL_PRIVINSTR_FAULT;
195 				break;
196 			case ILL_BADSTK:
197 				code = ILL_STACK;
198 				break;
199 			case ILL_ILLTRP:
200 				code = ILL_TRAP_FAULT(sip->si_trapno);
201 				break;
202 			default:
203 				code = ILL_ILLINSTR_FAULT;
204 				break;
205 			}
206 			break;
207 
208 		case SIGEMT:
209 			code = EMT_TAG;
210 			break;
211 
212 		case SIGFPE:
213 			switch (sip->si_code) {
214 			case FPE_INTDIV:
215 				code = FPE_INTDIV_TRAP;
216 				break;
217 			case FPE_INTOVF:
218 				code = FPE_INTOVF_TRAP;
219 				break;
220 			case FPE_FLTDIV:
221 				code = FPE_FLTDIV_TRAP;
222 				break;
223 			case FPE_FLTOVF:
224 				code = FPE_FLTOVF_TRAP;
225 				break;
226 			case FPE_FLTUND:
227 				code = FPE_FLTUND_TRAP;
228 				break;
229 			case FPE_FLTRES:
230 				code = FPE_FLTINEX_TRAP;
231 				break;
232 			default:
233 				code = FPE_FLTOPERR_TRAP;
234 				break;
235 			}
236 			break;
237 
238 		case SIGBUS:
239 			switch (sip->si_code) {
240 			case BUS_ADRALN:
241 				code = BUS_ALIGN;
242 				break;
243 			case BUS_ADRERR:
244 				code = BUS_HWERR;
245 				break;
246 			default:	/* BUS_OBJERR */
247 				code = FC_MAKE_ERR(sip->si_errno);
248 				break;
249 			}
250 			break;
251 
252 		case SIGSEGV:
253 			switch (sip->si_code) {
254 			case SEGV_MAPERR:
255 				code = SEGV_NOMAP;
256 				break;
257 			case SEGV_ACCERR:
258 				code = SEGV_PROT;
259 				break;
260 			default:
261 				code = FC_MAKE_ERR(sip->si_errno);
262 				break;
263 			}
264 			break;
265 
266 		default:
267 			addr = SIG_NOADDR;
268 			break;
269 		}
270 	}
271 
272 	(*_siguhandler[sig])(sig, code, &sc, addr);
273 
274 	if (sc.sc_onstack)
275 		ucp->uc_stack.ss_flags |= SS_ONSTACK;
276 	else
277 		ucp->uc_stack.ss_flags &= ~SS_ONSTACK;
278 	mask2set(sc.sc_mask, &ucp->uc_sigmask);
279 
280 #if defined(__sparc)
281 	ucp->uc_mcontext.gregs[REG_SP] = sc.sc_sp;
282 	ucp->uc_mcontext.gregs[REG_PC] = sc.sc_pc;
283 	ucp->uc_mcontext.gregs[REG_nPC] = sc.sc_npc;
284 #if defined(__sparcv9)
285 	ucp->uc_mcontext.gregs[REG_CCR] = sc.sc_psr;
286 #else
287 	ucp->uc_mcontext.gregs[REG_PSR] = sc.sc_psr;
288 #endif
289 	ucp->uc_mcontext.gregs[REG_G1] = sc.sc_g1;
290 	ucp->uc_mcontext.gregs[REG_O0] = sc.sc_o0;
291 #ifdef NEVER
292 	if (gwinswitch == 1) {
293 		int i, j;
294 
295 		ucp->uc_mcontext.gwins->wbcnt = sc.sc_wbcnt;
296 		/* XXX - should use bcopy to move this in bulk */
297 		for (i = 0; i < sc.sc_wbcnt; i++) {
298 			ucp->uc_mcontext.gwins->spbuf[i] = sc.sc_spbuf[i];
299 			for (j = 0; j < 8; j++)
300 				ucp->uc_mcontext.gwins->wbuf[i].rw_local[j] =
301 				    sc.sc_wbuf[i][j];
302 			for (j = 0; j < 8; j++)
303 				ucp->uc_mcontext.gwins->wbuf[i].rw_in[j] =
304 				    sc.sc_wbuf[i][j+8];
305 		}
306 	}
307 #endif
308 
309 	if (sig == SIGFPE) {
310 		if (ucp->uc_mcontext.fpregs.fpu_qcnt > 0) {
311 			ucp->uc_mcontext.fpregs.fpu_qcnt--;
312 			ucp->uc_mcontext.fpregs.fpu_q++;
313 		}
314 	}
315 #endif
316 
317 	(void) setcontext(ucp);
318 }
319 
320 #if defined(__sparc)
321 /*
322  * Emulate the special sigcleanup trap.
323  * This is only used by statically linked 4.x applications
324  * and thus is only called by the static BCP support.
325  * It lives here because of its close relationship with
326  * the ucbsigvechandler code above.
327  *
328  * It's used by 4.x applications to:
329  *	1. return from a signal handler (in __sigtramp)
330  *	2. [sig]longjmp
331  *	3. context switch, in the old 4.x liblwp
332  */
333 
334 void
335 __sigcleanup(struct sigcontext *scp)
336 {
337 	ucontext_t uc, *ucp;
338 	int sig;
339 
340 	/*
341 	 * If there's a pointer to a ucontext_t hiding in the sigcontext,
342 	 * we *must* use that to return, since it contains important data
343 	 * such as the original "out" registers when the signal occurred.
344 	 */
345 	if (scp->sc_wbcnt == sizeof (*ucp)) {
346 		sig = (int)(uintptr_t)scp->sc_spbuf[0];
347 		ucp = (ucontext_t *)scp->sc_spbuf[1];
348 	} else {
349 		/*
350 		 * Otherwise, use a local ucontext_t and
351 		 * initialize it with getcontext.
352 		 */
353 		sig = 0;
354 		ucp = &uc;
355 		(void) getcontext(ucp);
356 	}
357 
358 	if (scp->sc_onstack) {
359 		ucp->uc_stack.ss_flags |= SS_ONSTACK;
360 	} else
361 		ucp->uc_stack.ss_flags &= ~SS_ONSTACK;
362 	mask2set(scp->sc_mask, &ucp->uc_sigmask);
363 
364 	ucp->uc_mcontext.gregs[REG_SP] = scp->sc_sp;
365 	ucp->uc_mcontext.gregs[REG_PC] = scp->sc_pc;
366 	ucp->uc_mcontext.gregs[REG_nPC] = scp->sc_npc;
367 #if defined(__sparcv9)
368 	ucp->uc_mcontext.gregs[REG_CCR] = scp->sc_psr;
369 #else
370 	ucp->uc_mcontext.gregs[REG_PSR] = scp->sc_psr;
371 #endif
372 	ucp->uc_mcontext.gregs[REG_G1] = scp->sc_g1;
373 	ucp->uc_mcontext.gregs[REG_O0] = scp->sc_o0;
374 
375 	if (sig == SIGFPE) {
376 		if (ucp->uc_mcontext.fpregs.fpu_qcnt > 0) {
377 			ucp->uc_mcontext.fpregs.fpu_qcnt--;
378 			ucp->uc_mcontext.fpregs.fpu_q++;
379 		}
380 	}
381 	(void) setcontext(ucp);
382 	/* NOTREACHED */
383 }
384 #endif
385 
386 int
387 _sigsetmask(int mask)
388 {
389 	return (ucbsigsetmask(mask));
390 }
391 
392 int
393 ucbsigsetmask(int mask)
394 {
395 	sigset_t oset;
396 	sigset_t nset;
397 
398 	(void) _sigprocmask(0, (sigset_t *)0, &nset);
399 	mask2set(mask, &nset);
400 	(void) _sigprocmask(SIG_SETMASK, &nset, &oset);
401 	return (set2mask(&oset));
402 }
403 
404 int
405 _sigblock(int mask)
406 {
407 	return (ucbsigblock(mask));
408 }
409 
410 int
411 ucbsigblock(int mask)
412 {
413 	sigset_t oset;
414 	sigset_t nset;
415 
416 	(void) _sigprocmask(0, (sigset_t *)0, &nset);
417 	mask2set(mask, &nset);
418 	(void) _sigprocmask(SIG_BLOCK, &nset, &oset);
419 	return (set2mask(&oset));
420 }
421 
422 int
423 usigpause(int mask)
424 {
425 	return (ucbsigpause(mask));
426 }
427 
428 int
429 ucbsigpause(int mask)
430 {
431 	sigset_t set, oset;
432 	int ret;
433 
434 	(void) _sigprocmask(0, (sigset_t *)0, &set);
435 	oset = set;
436 	mask2set(mask, &set);
437 	ret = sigsuspend(&set);
438 	(void) _sigprocmask(SIG_SETMASK, &oset, (sigset_t *)0);
439 	return (ret);
440 }
441 
442 int
443 _sigvec(int sig, struct sigvec *nvec, struct sigvec *ovec)
444 {
445 	return (ucbsigvec(sig, nvec, ovec));
446 }
447 
448 int
449 ucbsigvec(int sig, struct sigvec *nvec, struct sigvec *ovec)
450 {
451 	struct sigaction nact;
452 	struct sigaction oact;
453 	struct sigaction *nactp;
454 	void (*ohandler)(int, int, struct sigcontext *, char *);
455 	void (*nhandler)(int, int, struct sigcontext *, char *);
456 
457 	if (sig <= 0 || sig >= NSIG) {
458 		errno = EINVAL;
459 		return (-1);
460 	}
461 
462 	if ((long)ovec == -1L || (long)nvec == -1L) {
463 		errno = EFAULT;
464 		return (-1);
465 	}
466 
467 	ohandler = _siguhandler[sig];
468 
469 	if (nvec) {
470 		(void) _sigaction(sig, (struct sigaction *)0, &nact);
471 		nhandler = nvec->sv_handler;
472 		/*
473 		 * To be compatible with the behavior of SunOS 4.x:
474 		 * If the new signal handler is SIG_IGN or SIG_DFL,
475 		 * do not change the signal's entry in the handler array.
476 		 * This allows a child of vfork(2) to set signal handlers
477 		 * to SIG_IGN or SIG_DFL without affecting the parent.
478 		 */
479 		if ((void (*)(int))(uintptr_t)nhandler != SIG_DFL &&
480 		    (void (*)(int))(uintptr_t)nhandler != SIG_IGN) {
481 			_siguhandler[sig] = nhandler;
482 			nact.sa_handler =
483 			    (void (*)(int))(uintptr_t)ucbsigvechandler;
484 		} else {
485 			nact.sa_handler = (void (*)(int))(uintptr_t)nhandler;
486 		}
487 		mask2set(nvec->sv_mask, &nact.sa_mask);
488 		if (sig == SIGKILL || sig == SIGSTOP)
489 			nact.sa_handler = SIG_DFL;
490 		nact.sa_flags = SA_SIGINFO;
491 		if (!(nvec->sv_flags & SV_INTERRUPT))
492 			nact.sa_flags |= SA_RESTART;
493 		if (nvec->sv_flags & SV_RESETHAND)
494 			nact.sa_flags |= SA_RESETHAND;
495 		if (nvec->sv_flags & SV_ONSTACK)
496 			nact.sa_flags |= SA_ONSTACK;
497 		nactp = &nact;
498 	} else
499 		nactp = (struct sigaction *)0;
500 
501 	if (_sigaction(sig, nactp, &oact) < 0) {
502 		_siguhandler[sig] = ohandler;
503 		return (-1);
504 	}
505 
506 	if (ovec) {
507 		if (oact.sa_handler == SIG_DFL || oact.sa_handler == SIG_IGN)
508 			ovec->sv_handler =
509 			    (void (*) (int, int, struct sigcontext *, char *))
510 			    oact.sa_handler;
511 		else
512 			ovec->sv_handler = ohandler;
513 		ovec->sv_mask = set2mask(&oact.sa_mask);
514 		ovec->sv_flags = 0;
515 		if (oact.sa_flags & SA_ONSTACK)
516 			ovec->sv_flags |= SV_ONSTACK;
517 		if (oact.sa_flags & SA_RESETHAND)
518 			ovec->sv_flags |= SV_RESETHAND;
519 		if (!(oact.sa_flags & SA_RESTART))
520 			ovec->sv_flags |= SV_INTERRUPT;
521 	}
522 
523 	return (0);
524 }
525 
526 int
527 _sigstack(struct sigstack *nss, struct sigstack *oss)
528 {
529 	struct sigaltstack nalt;
530 	struct sigaltstack oalt;
531 	struct sigaltstack *naltp;
532 
533 	if (nss) {
534 		/*
535 		 * XXX: assumes stack growth is down (like sparc)
536 		 */
537 		nalt.ss_sp = nss->ss_sp - SIGSTKSZ;
538 		nalt.ss_size = SIGSTKSZ;
539 		nalt.ss_flags = 0;
540 		naltp = &nalt;
541 	} else
542 		naltp = (struct sigaltstack *)0;
543 
544 	if (sigaltstack(naltp, &oalt) < 0)
545 		return (-1);
546 
547 	if (oss) {
548 		/*
549 		 * XXX: assumes stack growth is down (like sparc)
550 		 */
551 		oss->ss_sp = oalt.ss_sp + oalt.ss_size;
552 		oss->ss_onstack = ((oalt.ss_flags & SS_ONSTACK) != 0);
553 	}
554 
555 	return (0);
556 }
557 
558 void (*
559 ucbsignal(int s, void (*a)(int)))(int)
560 {
561 	struct sigvec osv;
562 	struct sigvec nsv;
563 	static int mask[NSIG];
564 	static int flags[NSIG];
565 
566 	nsv.sv_handler =
567 	    (void (*) (int, int, struct sigcontext *, char *))(uintptr_t)a;
568 	nsv.sv_mask = mask[s];
569 	nsv.sv_flags = flags[s];
570 	if (ucbsigvec(s, &nsv, &osv) < 0)
571 		return (SIG_ERR);
572 	if (nsv.sv_mask != osv.sv_mask || nsv.sv_flags != osv.sv_flags) {
573 		mask[s] = nsv.sv_mask = osv.sv_mask;
574 		flags[s] = nsv.sv_flags =
575 		    osv.sv_flags & ~(SV_RESETHAND|SV_INTERRUPT);
576 		if (ucbsigvec(s, &nsv, (struct sigvec *)0) < 0)
577 			return (SIG_ERR);
578 	}
579 	return ((void (*) (int)) osv.sv_handler);
580 }
581 
582 void (*
583 usignal(int s, void (*a) (int)))(int)
584 {
585 	return (ucbsignal(s, a));
586 }
587 
588 /*
589  * Set signal state to prevent restart of system calls
590  * after an instance of the indicated signal.
591  */
592 
593 int
594 _siginterrupt(int sig, int flag)
595 {
596 	return (ucbsiginterrupt(sig, flag));
597 }
598 
599 int
600 ucbsiginterrupt(int sig, int flag)
601 {
602 	struct sigvec sv;
603 	int ret;
604 
605 	if ((ret = ucbsigvec(sig, 0, &sv)) < 0)
606 		return (ret);
607 	if (flag)
608 		sv.sv_flags |= SV_INTERRUPT;
609 	else
610 		sv.sv_flags &= ~SV_INTERRUPT;
611 	return (ucbsigvec(sig, &sv, 0));
612 }
613