trap.c revision 1.44
1/*	$OpenBSD: trap.c,v 1.44 2002/07/21 11:47:39 mickey Exp $	*/
2
3/*
4 * Copyright (c) 1998-2001 Michael Shalayeff
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 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *	This product includes software developed by Michael Shalayeff.
18 * 4. The name of the author may not be used to endorse or promote products
19 *    derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33/* #define TRAPDEBUG */
34
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/syscall.h>
38#include <sys/ktrace.h>
39#include <sys/proc.h>
40#include <sys/signalvar.h>
41#include <sys/user.h>
42
43#include <net/netisr.h>
44
45#include "systrace.h"
46#include <dev/systrace.h>
47
48#include <uvm/uvm.h>
49
50#include <machine/autoconf.h>
51
52#ifdef DDB
53#include <machine/db_machdep.h>
54#ifdef TRAPDEBUG
55#include <ddb/db_output.h>
56#endif
57#endif
58
59const char *trap_type[] = {
60	"invalid",
61	"HPMC",
62	"power failure",
63	"recovery counter",
64	"external interrupt",
65	"LPMC",
66	"ITLB miss fault",
67	"instruction protection",
68	"Illegal instruction",
69	"break instruction",
70	"privileged operation",
71	"privileged register",
72	"overflow",
73	"conditional",
74	"assist exception",
75	"DTLB miss",
76	"ITLB non-access miss",
77	"DTLB non-access miss",
78	"data protection/rights/alignment",
79	"data break",
80	"TLB dirty",
81	"page reference",
82	"assist emulation",
83	"higher-priv transfer",
84	"lower-priv transfer",
85	"taken branch",
86	"data access rights",
87	"data protection",
88	"unaligned data ref",
89};
90int trap_types = sizeof(trap_type)/sizeof(trap_type[0]);
91
92int want_resched, astpending;
93
94void syscall(struct trapframe *frame, int *args);
95
96static __inline void
97userret (struct proc *p, register_t pc, u_quad_t oticks)
98{
99	int sig;
100
101	/* take pending signals */
102	while ((sig = CURSIG(p)) != 0)
103		postsig(sig);
104
105	p->p_priority = p->p_usrpri;
106	if (want_resched) {
107		/*
108		 * We're being preempted.
109		 */
110		preempt(NULL);
111		while ((sig = CURSIG(p)) != 0)
112			postsig(sig);
113	}
114
115	/*
116	 * If profiling, charge recent system time to the trapped pc.
117	 */
118	if (p->p_flag & P_PROFIL) {
119		extern int psratio;
120
121		addupc_task(p, pc, (int)(p->p_sticks - oticks) * psratio);
122	}
123
124	curpriority = p->p_priority;
125}
126
127void
128trap(type, frame)
129	int type;
130	struct trapframe *frame;
131{
132	extern u_int32_t sir;
133	struct proc *p = curproc;
134	struct pcb *pcbp;
135	vaddr_t va;
136	struct vm_map *map;
137	struct vmspace *vm;
138	register vm_prot_t vftype;
139	register pa_space_t space;
140	union sigval sv;
141	u_int opcode;
142	int ret, s, si, trapnum;
143	const char *tts;
144
145	trapnum = type & ~T_USER;
146	opcode = frame->tf_iir;
147	if (trapnum == T_ITLBMISS || trapnum == T_ITLBMISSNA) {
148		va = frame->tf_iioq_head;
149		space = frame->tf_iisq_head;
150		vftype = VM_PROT_EXECUTE;
151	} else {
152		va = frame->tf_ior;
153		space = frame->tf_isr;
154		vftype = inst_store(opcode) ? VM_PROT_WRITE : VM_PROT_READ;
155	}
156
157	if (frame->tf_flags & TFF_LAST)
158		p->p_md.md_regs = frame;
159
160#ifdef TRAPDEBUG
161	if (trapnum > trap_types)
162		tts = "reserved";
163	else
164		tts = trap_type[trapnum];
165
166	if (trapnum != T_INTERRUPT && trapnum != T_IBREAK)
167		db_printf("trap: %x, %s for %x:%x at %x:%x, fl=%x, fp=%p\n",
168		    type, tts, space, va, frame->tf_iisq_head,
169		    frame->tf_iioq_head, frame->tf_flags, frame);
170	else if (trapnum  == T_IBREAK)
171		db_printf("trap: break instruction %x:%x at %x:%x, fp=%p\n",
172		    break5(opcode), break13(opcode),
173		    frame->tf_iisq_head, frame->tf_iioq_head, frame);
174
175	{
176		extern int etext;
177		if (frame < (struct trapframe *)&etext) {
178			printf("trap: bogus frame ptr %p\n", frame);
179			goto dead_end;
180		}
181	}
182#endif
183	switch (type) {
184	case T_NONEXIST:
185	case T_NONEXIST|T_USER:
186#ifndef DDB
187		/* we've got screwed up by the central scrutinizer */
188		panic ("trap: elvis has just left the building!");
189		break;
190#else
191		goto dead_end;
192#endif
193	case T_RECOVERY:
194	case T_RECOVERY|T_USER:
195#ifndef DDB
196		/* XXX will implement later */
197		printf ("trap: handicapped");
198		break;
199#else
200		goto dead_end;
201#endif
202
203#ifdef DIAGNOSTIC
204	case T_EXCEPTION:
205		panic("FPU/SFU emulation botch");
206
207		/* these just can't happen ever */
208	case T_PRIV_OP:
209	case T_PRIV_REG:
210		/* these just can't make it to the trap() ever */
211	case T_HPMC:      case T_HPMC | T_USER:
212	case T_EMULATION: case T_EMULATION | T_USER:
213#endif
214	case T_IBREAK:
215	case T_DATALIGN:
216	case T_DBREAK:
217	dead_end:
218#ifdef DDB
219		if (kdb_trap (type, va, frame)) {
220			if (type == T_IBREAK) {
221				/* skip break instruction */
222				frame->tf_iioq_head = frame->tf_iioq_tail;
223				frame->tf_iioq_tail += 4;
224			}
225			return;
226		}
227#else
228		if (type == T_DATALIGN)
229			panic ("trap: %s at 0x%x", tts, va);
230		else
231			panic ("trap: no debugger for \"%s\" (%d)", tts, type);
232#endif
233		break;
234
235	case T_IBREAK | T_USER:
236	case T_DBREAK | T_USER:
237		/* pass to user debugger */
238		break;
239
240	case T_EXCEPTION | T_USER:	/* co-proc assist trap */
241		sv.sival_int = va;
242		trapsignal(p, SIGFPE, type &~ T_USER, FPE_FLTINV, sv);
243		break;
244
245	case T_OVERFLOW | T_USER:
246		sv.sival_int = va;
247		trapsignal(p, SIGFPE, type &~ T_USER, FPE_INTOVF, sv);
248		break;
249
250	case T_CONDITION | T_USER:
251		break;
252
253	case T_ILLEGAL | T_USER:
254		sv.sival_int = va;
255		trapsignal(p, SIGILL, type &~ T_USER, ILL_ILLOPC, sv);
256		break;
257
258	case T_PRIV_OP | T_USER:
259		sv.sival_int = va;
260		trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVOPC, sv);
261		break;
262
263	case T_PRIV_REG | T_USER:
264		sv.sival_int = va;
265		trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVREG, sv);
266		break;
267
268		/* these should never got here */
269	case T_HIGHERPL | T_USER:
270	case T_LOWERPL | T_USER:
271		sv.sival_int = va;
272		trapsignal(p, SIGSEGV, type &~ T_USER, SEGV_ACCERR, sv);
273		break;
274
275	case T_IPROT | T_USER:
276	case T_DPROT | T_USER:
277		sv.sival_int = va;
278		trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv);
279		break;
280
281	case T_DATACC:   	case T_USER | T_DATACC:
282	case T_ITLBMISS:	case T_USER | T_ITLBMISS:
283	case T_DTLBMISS:	case T_USER | T_DTLBMISS:
284	case T_ITLBMISSNA:	case T_USER | T_ITLBMISSNA:
285	case T_DTLBMISSNA:	case T_USER | T_DTLBMISSNA:
286	case T_TLB_DIRTY:	case T_USER | T_TLB_DIRTY:
287		va = hppa_trunc_page(va);
288		vm = p->p_vmspace;
289
290		if (!vm) {
291#ifdef TRAPDEBUG
292			printf("trap: no vm, p=%p\n", p);
293#endif
294			goto dead_end;
295		}
296
297		/*
298		 * it could be a kernel map for exec_map faults
299		 */
300		if (!(type & T_USER) && space == HPPA_SID_KERNEL)
301			map = kernel_map;
302		else
303			map = &vm->vm_map;
304
305		if (map->pmap->pm_space != space) {
306#ifdef TRAPDEBUG
307			printf("trap: space missmatch %d != %d\n",
308			    space, map->pmap->pm_space);
309#endif
310			/* actually dump the user, crap the kernel */
311			goto dead_end;
312		}
313
314#ifdef TRAPDEBUG
315		if (space == -1) {
316			extern int pmapdebug;
317			pmapdebug = 0xffffff;
318		}
319#endif
320
321		ret = uvm_fault(map, va, 0, vftype);
322
323#ifdef TRAPDEBUG
324		if (space == -1) {
325			extern int pmapdebug;
326			pmapdebug = 0;
327		}
328
329		printf("uvm_fault(%p, %x, %d, %d)=%d\n",
330		    map, va, 0, vftype, ret);
331#endif
332
333		/*
334		 * If this was a stack access we keep track of the maximum
335		 * accessed stack size.  Also, if uvm_fault gets a protection
336		 * failure it is due to accessing the stack region outside
337		 * the current limit and we need to reflect that as an access
338		 * error.
339		 */
340		if (va >= (vaddr_t)vm->vm_maxsaddr + vm->vm_ssize) {
341			if (ret == 0) {
342				vsize_t nss = btoc(va - USRSTACK + NBPG);
343				if (nss > vm->vm_ssize)
344					vm->vm_ssize = nss;
345			} else if (ret == EACCES)
346				ret = EFAULT;
347		}
348
349		if (ret != 0) {
350			if (type & T_USER) {
351				sv.sival_int = frame->tf_ior;
352				trapsignal(p, SIGSEGV, vftype, SEGV_MAPERR, sv);
353			} else {
354				if (p && p->p_addr->u_pcb.pcb_onfault) {
355					pcbp = &p->p_addr->u_pcb;
356					frame->tf_iioq_tail = 4 +
357					    (frame->tf_iioq_head =
358						pcbp->pcb_onfault);
359					break;
360				}
361#if 0
362if (kdb_trap (type, va, frame))
363	return;
364#else
365				panic("trap: uvm_fault(%p, %x, %d, %d): %d",
366				    map, va, 0, vftype, ret);
367#endif
368			}
369		}
370		break;
371
372	case T_DATALIGN | T_USER:
373		sv.sival_int = va;
374		trapsignal(p, SIGBUS, vftype, BUS_ADRALN, sv);
375		break;
376
377	case T_INTERRUPT:
378	case T_INTERRUPT|T_USER:
379		frame->tf_flags |= TFF_INTR;
380		cpu_intr(frame);
381#if 0
382if (kdb_trap (type, va, frame))
383return;
384#endif
385		/* FALLTHROUGH */
386	case T_LOWERPL:
387		__asm __volatile (
388		    "ldcws 0(%1), %0" : "=&r" (si) : "r" (&sir) : "memory");
389		if (si & SIR_CLOCK) {
390			s = splsoftclock();
391			softclock();
392			splx(s);
393		}
394
395		if (si & SIR_NET) {
396			register int ni;
397			/* use atomic "load & clear" */
398			__asm __volatile (
399			    "ldcws 0(%1), %0"
400			    : "=&r" (ni) : "r" (&netisr) : "memory");
401			s = splnet();
402#define	DONETISR(m,c) if (ni & (1 << (m))) c()
403#include <net/netisr_dispatch.h>
404			splx(s);
405		}
406		break;
407
408	case T_DPROT:
409	case T_IPROT:
410	case T_OVERFLOW:
411	case T_CONDITION:
412	case T_ILLEGAL:
413	case T_HIGHERPL:
414	case T_TAKENBR:
415	case T_POWERFAIL:
416	case T_LPMC:
417	case T_PAGEREF:
418	case T_DATAPID:  	case T_DATAPID  | T_USER:
419		if (0 /* T-chip */) {
420			break;
421		}
422		/* FALLTHROUGH to unimplemented */
423	default:
424#if 0
425if (kdb_trap (type, va, frame))
426	return;
427#endif
428		panic ("trap: unimplemented \'%s\' (%d)", tts, type);
429	}
430
431	if (type & T_USER)
432		userret(p, p->p_md.md_regs->tf_iioq_head, 0);
433}
434
435void
436child_return(arg)
437	void *arg;
438{
439	struct proc *p = (struct proc *)arg;
440	userret(p, p->p_md.md_regs->tf_iioq_head, 0);
441#ifdef KTRACE
442	if (KTRPOINT(p, KTR_SYSRET))
443		ktrsysret(p, SYS_fork, 0, 0);
444#endif
445}
446
447/*
448 * call actual syscall routine
449 * from the low-level syscall handler:
450 * - all HPPA_FRAME_NARGS syscall's arguments supposed to be copied onto
451 *   our stack, this wins compared to copyin just needed amount anyway
452 * - register args are copied onto stack too
453 */
454void
455syscall(frame, args)
456	struct trapframe *frame;
457	int *args;
458{
459	register struct proc *p;
460	register const struct sysent *callp;
461	int nsys, code, argsize, error;
462	int rval[2];
463
464	uvmexp.syscalls++;
465
466	if (!USERMODE(frame->tf_iioq_head))
467		panic("syscall");
468
469	p = curproc;
470	p->p_md.md_regs = frame;
471	nsys = p->p_emul->e_nsysent;
472	callp = p->p_emul->e_sysent;
473	code = frame->tf_t1;
474	switch (code) {
475	case SYS_syscall:
476		code = *args;
477		args += 1;
478		break;
479	case SYS___syscall:
480		if (callp != sysent)
481			break;
482		code = *args;
483		args += 2;
484	}
485
486	if (code < 0 || code >= nsys)
487		callp += p->p_emul->e_nosys;	/* bad syscall # */
488	else
489		callp += code;
490	argsize = callp->sy_argsize;
491
492#ifdef SYSCALL_DEBUG
493	scdebug_call(p, code, args);
494#endif
495#ifdef KTRACE
496	if (KTRPOINT(p, KTR_SYSCALL))
497		ktrsyscall(p, code, argsize, args);
498#endif
499
500	rval[0] = 0;
501	rval[1] = 0;
502#if NSYSTRACE > 0
503	if (ISSET(p->p_flag, P_SYSTRACE))
504		error = systrace_redirect(code, p, args, rval);
505	else
506#endif
507		error = (*callp->sy_call)(p, args, rval);
508	switch (error) {
509	case 0:
510		p = curproc;			/* changes on exec() */
511		frame = p->p_md.md_regs;
512		frame->tf_ret0 = rval[0];
513		frame->tf_ret1 = rval[1];
514		frame->tf_t1 = 0;
515		break;
516	case ERESTART:
517		frame->tf_iioq_head -= 12;
518		frame->tf_iioq_tail -= 12;
519		break;
520	case EJUSTRETURN:
521		p = curproc;
522		break;
523	default:
524		if (p->p_emul->e_errno)
525			error = p->p_emul->e_errno[error];
526		frame->tf_t1 = error;
527		break;
528	}
529#ifdef SYSCALL_DEBUG
530	scdebug_ret(p, code, error, rval);
531#endif
532	userret(p, frame->tf_iioq_head, 0);
533#ifdef KTRACE
534	if (KTRPOINT(p, KTR_SYSRET))
535		ktrsysret(p, code, error, rval[0]);
536#endif
537}
538