trap.c revision 1.85
1331722Seadler/*	$OpenBSD: trap.c,v 1.85 2005/04/07 00:23:51 mickey Exp $	*/
2239281Sgonzo
3239281Sgonzo/*
4239281Sgonzo * Copyright (c) 1998-2004 Michael Shalayeff
5239281Sgonzo * All rights reserved.
6239281Sgonzo *
7239281Sgonzo * Redistribution and use in source and binary forms, with or without
8239281Sgonzo * modification, are permitted provided that the following conditions
9239281Sgonzo * are met:
10239281Sgonzo * 1. Redistributions of source code must retain the above copyright
11239281Sgonzo *    notice, this list of conditions and the following disclaimer.
12239281Sgonzo * 2. Redistributions in binary form must reproduce the above copyright
13239281Sgonzo *    notice, this list of conditions and the following disclaimer in the
14239281Sgonzo *    documentation and/or other materials provided with the distribution.
15239281Sgonzo *
16239281Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17239281Sgonzo * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18239281Sgonzo * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19239281Sgonzo * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
20239281Sgonzo * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21239281Sgonzo * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22239281Sgonzo * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23239281Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24239281Sgonzo * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25239281Sgonzo * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26239281Sgonzo * THE POSSIBILITY OF SUCH DAMAGE.
27239281Sgonzo */
28239281Sgonzo
29239281Sgonzo/* #define TRAPDEBUG */
30239281Sgonzo
31239281Sgonzo#include <sys/param.h>
32239281Sgonzo#include <sys/systm.h>
33239281Sgonzo#include <sys/syscall.h>
34239281Sgonzo#include <sys/ktrace.h>
35239281Sgonzo#include <sys/proc.h>
36239281Sgonzo#include <sys/signalvar.h>
37239281Sgonzo#include <sys/user.h>
38239281Sgonzo
39239281Sgonzo#include <net/netisr.h>
40239281Sgonzo
41239281Sgonzo#include "systrace.h"
42239281Sgonzo#include <dev/systrace.h>
43239281Sgonzo
44239281Sgonzo#include <uvm/uvm.h>
45239281Sgonzo
46239281Sgonzo#include <machine/autoconf.h>
47239281Sgonzo
48239281Sgonzo#include <machine/db_machdep.h>	/* XXX always needed for inst_store() */
49239281Sgonzo#ifdef DDB
50239281Sgonzo#ifdef TRAPDEBUG
51239281Sgonzo#include <ddb/db_output.h>
52239281Sgonzo#endif
53239281Sgonzo#endif
54239281Sgonzo
55239281Sgonzoconst char *trap_type[] = {
56239281Sgonzo	"invalid",
57239281Sgonzo	"HPMC",
58239281Sgonzo	"power failure",
59239281Sgonzo	"recovery counter",
60239281Sgonzo	"external interrupt",
61239281Sgonzo	"LPMC",
62239281Sgonzo	"ITLB miss fault",
63239281Sgonzo	"instruction protection",
64239281Sgonzo	"Illegal instruction",
65283276Sgonzo	"break instruction",
66239281Sgonzo	"privileged operation",
67239281Sgonzo	"privileged register",
68239281Sgonzo	"overflow",
69239281Sgonzo	"conditional",
70239281Sgonzo	"assist exception",
71239281Sgonzo	"DTLB miss",
72239281Sgonzo	"ITLB non-access miss",
73239281Sgonzo	"DTLB non-access miss",
74239281Sgonzo	"data protection/rights/alignment",
75239281Sgonzo	"data break",
76239281Sgonzo	"TLB dirty",
77239281Sgonzo	"page reference",
78239281Sgonzo	"assist emulation",
79239281Sgonzo	"higher-priv transfer",
80239281Sgonzo	"lower-priv transfer",
81239281Sgonzo	"taken branch",
82239281Sgonzo	"data access rights",
83239281Sgonzo	"data protection",
84239281Sgonzo	"unaligned data ref",
85239281Sgonzo};
86239281Sgonzoint trap_types = sizeof(trap_type)/sizeof(trap_type[0]);
87239281Sgonzo
88239281Sgonzoint want_resched, astpending;
89239281Sgonzo
90261410Sian#define	frame_regmap(tf,r)	(((u_int *)(tf))[hppa_regmap[(r)]])
91261410Sianu_char hppa_regmap[32] = {
92261410Sian	offsetof(struct trapframe, tf_pad[0]) / 4,	/* r0 XXX */
93283276Sgonzo	offsetof(struct trapframe, tf_r1) / 4,
94239281Sgonzo	offsetof(struct trapframe, tf_rp) / 4,
95239281Sgonzo	offsetof(struct trapframe, tf_r3) / 4,
96283276Sgonzo	offsetof(struct trapframe, tf_r4) / 4,
97283276Sgonzo	offsetof(struct trapframe, tf_r5) / 4,
98283276Sgonzo	offsetof(struct trapframe, tf_r6) / 4,
99283276Sgonzo	offsetof(struct trapframe, tf_r7) / 4,
100239281Sgonzo	offsetof(struct trapframe, tf_r8) / 4,
101239281Sgonzo	offsetof(struct trapframe, tf_r9) / 4,
102239281Sgonzo	offsetof(struct trapframe, tf_r10) / 4,
103239281Sgonzo	offsetof(struct trapframe, tf_r11) / 4,
104239281Sgonzo	offsetof(struct trapframe, tf_r12) / 4,
105239281Sgonzo	offsetof(struct trapframe, tf_r13) / 4,
106239281Sgonzo	offsetof(struct trapframe, tf_r14) / 4,
107239281Sgonzo	offsetof(struct trapframe, tf_r15) / 4,
108239281Sgonzo	offsetof(struct trapframe, tf_r16) / 4,
109239281Sgonzo	offsetof(struct trapframe, tf_r17) / 4,
110239281Sgonzo	offsetof(struct trapframe, tf_r18) / 4,
111239281Sgonzo	offsetof(struct trapframe, tf_t4) / 4,
112299069Spfg	offsetof(struct trapframe, tf_t3) / 4,
113239281Sgonzo	offsetof(struct trapframe, tf_t2) / 4,
114239281Sgonzo	offsetof(struct trapframe, tf_t1) / 4,
115239281Sgonzo	offsetof(struct trapframe, tf_arg3) / 4,
116239281Sgonzo	offsetof(struct trapframe, tf_arg2) / 4,
117239281Sgonzo	offsetof(struct trapframe, tf_arg1) / 4,
118239281Sgonzo	offsetof(struct trapframe, tf_arg0) / 4,
119239281Sgonzo	offsetof(struct trapframe, tf_dp) / 4,
120239281Sgonzo	offsetof(struct trapframe, tf_ret0) / 4,
121239281Sgonzo	offsetof(struct trapframe, tf_ret1) / 4,
122239281Sgonzo	offsetof(struct trapframe, tf_sp) / 4,
123239281Sgonzo	offsetof(struct trapframe, tf_r31) / 4,
124239281Sgonzo};
125239281Sgonzo
126239281Sgonzovoid
127239281Sgonzouserret(struct proc *p, register_t pc, u_quad_t oticks)
128239281Sgonzo{
129239281Sgonzo	int sig;
130239281Sgonzo
131239281Sgonzo	/* take pending signals */
132310856Sloos	while ((sig = CURSIG(p)) != 0)
133310856Sloos		postsig(sig);
134310856Sloos
135310856Sloos	p->p_priority = p->p_usrpri;
136239281Sgonzo	if (astpending) {
137239281Sgonzo		astpending = 0;
138239281Sgonzo		if (p->p_flag & P_OWEUPC) {
139239281Sgonzo			p->p_flag &= ~P_OWEUPC;
140239281Sgonzo			ADDUPROF(p);
141239281Sgonzo		}
142239281Sgonzo	}
143239281Sgonzo	if (want_resched) {
144239281Sgonzo		/*
145239281Sgonzo		 * We're being preempted.
146239281Sgonzo		 */
147239281Sgonzo		preempt(NULL);
148239281Sgonzo		while ((sig = CURSIG(p)) != 0)
149239281Sgonzo			postsig(sig);
150239281Sgonzo	}
151239281Sgonzo
152239281Sgonzo	/*
153239281Sgonzo	 * If profiling, charge recent system time to the trapped pc.
154239281Sgonzo	 */
155239281Sgonzo	if (p->p_flag & P_PROFIL) {
156239281Sgonzo		extern int psratio;
157239281Sgonzo
158239281Sgonzo		addupc_task(p, pc, (int)(p->p_sticks - oticks) * psratio);
159239281Sgonzo	}
160239281Sgonzo
161239281Sgonzo	curpriority = p->p_priority;
162283276Sgonzo}
163239281Sgonzo
164239281Sgonzovoid
165239281Sgonzotrap(type, frame)
166239281Sgonzo	int type;
167239281Sgonzo	struct trapframe *frame;
168239281Sgonzo{
169239281Sgonzo	struct proc *p = curproc;
170239281Sgonzo	vaddr_t va;
171239281Sgonzo	struct vm_map *map;
172239281Sgonzo	struct vmspace *vm;
173239281Sgonzo	register vm_prot_t vftype;
174295660Sskra	register pa_space_t space;
175295660Sskra	union sigval sv;
176	u_int opcode;
177	int ret, trapnum;
178	const char *tts;
179	vm_fault_t fault = VM_FAULT_INVALID;
180#ifdef DIAGNOSTIC
181	int oldcpl = cpl;
182#endif
183
184	trapnum = type & ~T_USER;
185	opcode = frame->tf_iir;
186	if (trapnum <= T_EXCEPTION || trapnum == T_HIGHERPL ||
187	    trapnum == T_LOWERPL || trapnum == T_TAKENBR ||
188	    trapnum == T_IDEBUG || trapnum == T_PERFMON) {
189		va = frame->tf_iioq_head;
190		space = frame->tf_iisq_head;
191		vftype = UVM_PROT_EXEC;
192	} else {
193		va = frame->tf_ior;
194		space = frame->tf_isr;
195		if (va == frame->tf_iioq_head)
196			vftype = UVM_PROT_EXEC;
197		else if (inst_store(opcode))
198			vftype = UVM_PROT_WRITE;
199		else
200			vftype = UVM_PROT_READ;
201	}
202
203	if (frame->tf_flags & TFF_LAST)
204		p->p_md.md_regs = frame;
205
206	if (trapnum > trap_types)
207		tts = "reserved";
208	else
209		tts = trap_type[trapnum];
210
211#ifdef TRAPDEBUG
212	if (trapnum != T_INTERRUPT && trapnum != T_IBREAK)
213		db_printf("trap: %x, %s for %x:%x at %x:%x, fl=%x, fp=%p\n",
214		    type, tts, space, va, frame->tf_iisq_head,
215		    frame->tf_iioq_head, frame->tf_flags, frame);
216	else if (trapnum  == T_IBREAK)
217		db_printf("trap: break instruction %x:%x at %x:%x, fp=%p\n",
218		    break5(opcode), break13(opcode),
219		    frame->tf_iisq_head, frame->tf_iioq_head, frame);
220
221	{
222		extern int etext;
223		if (frame < (struct trapframe *)&etext) {
224			printf("trap: bogus frame ptr %p\n", frame);
225			goto dead_end;
226		}
227	}
228#endif
229	if (trapnum != T_INTERRUPT) {
230		uvmexp.traps++;
231		mtctl(frame->tf_eiem, CR_EIEM);
232	}
233
234	switch (type) {
235	case T_NONEXIST:
236	case T_NONEXIST | T_USER:
237		/* we've got screwed up by the central scrutinizer */
238		printf("trap: elvis has just left the building!\n");
239		goto dead_end;
240
241	case T_RECOVERY:
242	case T_RECOVERY | T_USER:
243		/* XXX will implement later */
244		printf("trap: handicapped");
245		goto dead_end;
246
247#ifdef DIAGNOSTIC
248	case T_EXCEPTION:
249		panic("FPU/SFU emulation botch");
250
251		/* these just can't happen ever */
252	case T_PRIV_OP:
253	case T_PRIV_REG:
254		/* these just can't make it to the trap() ever */
255	case T_HPMC:
256	case T_HPMC | T_USER:
257#endif
258	case T_IBREAK:
259	case T_DATALIGN:
260	case T_DBREAK:
261	dead_end:
262#ifdef DDB
263		if (kdb_trap (type, va, frame)) {
264			if (type == T_IBREAK) {
265				/* skip break instruction */
266				frame->tf_iioq_head = frame->tf_iioq_tail;
267				frame->tf_iioq_tail += 4;
268			}
269			return;
270		}
271#else
272		if (type == T_DATALIGN)
273			panic ("trap: %s at 0x%x", tts, va);
274		else
275			panic ("trap: no debugger for \"%s\" (%d)", tts, type);
276#endif
277		break;
278
279	case T_IBREAK | T_USER:
280	case T_DBREAK | T_USER:
281		/* pass to user debugger */
282		trapsignal(p, SIGTRAP, type &~ T_USER, TRAP_BRKPT, sv);
283		break;
284
285	case T_EXCEPTION | T_USER: {
286		u_int64_t *fpp = (u_int64_t *)frame->tf_cr30;
287		u_int32_t *pex;
288		int i, flt;
289
290		pex = (u_int32_t *)&fpp[0];
291		for (i = 0, pex++; i < 7 && !*pex; i++, pex++);
292		flt = 0;
293		if (i < 7) {
294			u_int32_t stat = HPPA_FPU_OP(*pex);
295			if (stat & HPPA_FPU_UNMPL)
296				flt = FPE_FLTINV;
297			else if (stat & (HPPA_FPU_V << 1))
298				flt = FPE_FLTINV;
299			else if (stat & (HPPA_FPU_Z << 1))
300				flt = FPE_FLTDIV;
301			else if (stat & (HPPA_FPU_I << 1))
302				flt = FPE_FLTRES;
303			else if (stat & (HPPA_FPU_O << 1))
304				flt = FPE_FLTOVF;
305			else if (stat & (HPPA_FPU_U << 1))
306				flt = FPE_FLTUND;
307			/* still left: under/over-flow w/ inexact */
308
309			/* cleanup exceptions (XXX deliver all ?) */
310			while (i++ < 7)
311				*pex++ = 0;
312		}
313		/* reset the trap flag, as if there was none */
314		fpp[0] &= ~(((u_int64_t)HPPA_FPU_T) << 32);
315		/* flush out, since load is done from phys, only 4 regs */
316		fdcache(HPPA_SID_KERNEL, (vaddr_t)fpp, 8 * 4);
317
318		sv.sival_int = va;
319		trapsignal(p, SIGFPE, type &~ T_USER, flt, sv);
320		}
321		break;
322
323	case T_EMULATION:
324		panic("trap: emulation trap in the kernel");
325		break;
326
327	case T_EMULATION | T_USER:
328		sv.sival_int = va;
329		trapsignal(p, SIGILL, type &~ T_USER, ILL_COPROC, sv);
330		break;
331
332	case T_OVERFLOW | T_USER:
333		sv.sival_int = va;
334		trapsignal(p, SIGFPE, type &~ T_USER, FPE_INTOVF, sv);
335		break;
336
337	case T_CONDITION | T_USER:
338		sv.sival_int = va;
339		trapsignal(p, SIGFPE, type &~ T_USER, FPE_INTDIV, sv);
340		break;
341
342	case T_PRIV_OP | T_USER:
343		sv.sival_int = va;
344		trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVOPC, sv);
345		break;
346
347	case T_PRIV_REG | T_USER:
348		sv.sival_int = va;
349		trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVREG, sv);
350		break;
351
352		/* these should never got here */
353	case T_HIGHERPL | T_USER:
354	case T_LOWERPL | T_USER:
355		sv.sival_int = va;
356		trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv);
357		break;
358
359	case T_IPROT | T_USER:
360	case T_DPROT | T_USER:
361		sv.sival_int = va;
362		trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv);
363		break;
364
365	case T_ITLBMISSNA:
366	case T_ITLBMISSNA | T_USER:
367	case T_DTLBMISSNA:
368	case T_DTLBMISSNA | T_USER:
369		if (space == HPPA_SID_KERNEL)
370			map = kernel_map;
371		else {
372			vm = p->p_vmspace;
373			map = &vm->vm_map;
374		}
375
376		if ((opcode & 0xfc003fc0) == 0x04001340) {
377			/* lpa failure case */
378			frame_regmap(frame, opcode & 0x1f) = 0;
379			frame->tf_ipsw |= PSL_N;
380		} else if ((opcode & 0xfc001f80) == 0x04001180) {
381			int pl;
382
383			/* dig probe[rw]i? insns */
384			if (opcode & 0x2000)
385				pl = (opcode >> 16) & 3;
386			else
387				pl = frame_regmap(frame,
388				    (opcode >> 16) & 0x1f) & 3;
389
390			if ((type & T_USER && space == HPPA_SID_KERNEL) ||
391			    (frame->tf_iioq_head & 3) != pl ||
392			    (type & T_USER && va >= VM_MAXUSER_ADDRESS) ||
393			    uvm_fault(map, hppa_trunc_page(va), fault,
394			     opcode & 0x40? UVM_PROT_WRITE : UVM_PROT_READ)) {
395				frame_regmap(frame, opcode & 0x1f) = 0;
396				frame->tf_ipsw |= PSL_N;
397			}
398		} else if (type & T_USER) {
399			sv.sival_int = va;
400			trapsignal(p, SIGILL, type & ~T_USER, ILL_ILLTRP, sv);
401		} else
402			panic("trap: %s @ 0x%x:0x%x for 0x%x:0x%x irr 0x%08x\n",
403			    tts, frame->tf_iisq_head, frame->tf_iioq_head,
404			    space, va, opcode);
405		break;
406
407	case T_TLB_DIRTY:
408	case T_TLB_DIRTY | T_USER:
409	case T_DATACC:
410	case T_DATACC | T_USER:
411		fault = VM_FAULT_PROTECT;
412	case T_ITLBMISS:
413	case T_ITLBMISS | T_USER:
414	case T_DTLBMISS:
415	case T_DTLBMISS | T_USER:
416		/*
417		 * it could be a kernel map for exec_map faults
418		 */
419		if (space == HPPA_SID_KERNEL)
420			map = kernel_map;
421		else {
422			vm = p->p_vmspace;
423			map = &vm->vm_map;
424		}
425
426		/*
427		 * user faults out of user addr space are always a fail,
428		 * this happens on va >= VM_MAXUSER_ADDRESS, where
429		 * space id will be zero and therefore cause
430		 * a misbehave lower in the code.
431		 *
432		 * also check that faulted space id matches the curproc.
433		 */
434		if ((type & T_USER && va >= VM_MAXUSER_ADDRESS) ||
435		   (type & T_USER && map->pmap->pm_space != space)) {
436			sv.sival_int = va;
437			trapsignal(p, SIGSEGV, vftype, SEGV_MAPERR, sv);
438			break;
439		}
440
441		ret = uvm_fault(map, hppa_trunc_page(va), fault, vftype);
442
443		/*
444		 * If this was a stack access we keep track of the maximum
445		 * accessed stack size.  Also, if uvm_fault gets a protection
446		 * failure it is due to accessing the stack region outside
447		 * the current limit and we need to reflect that as an access
448		 * error.
449		 */
450		if (space != HPPA_SID_KERNEL &&
451		    va < (vaddr_t)vm->vm_minsaddr) {
452			if (ret == 0)
453				uvm_grow(p, va);
454			else if (ret == EACCES)
455				ret = EFAULT;
456		}
457
458		if (ret != 0) {
459			if (type & T_USER) {
460				sv.sival_int = va;
461				trapsignal(p, SIGSEGV, vftype,
462				    ret == EACCES? SEGV_ACCERR : SEGV_MAPERR,
463				    sv);
464			} else {
465				if (p && p->p_addr->u_pcb.pcb_onfault) {
466					frame->tf_iioq_tail = 4 +
467					    (frame->tf_iioq_head =
468						p->p_addr->u_pcb.pcb_onfault);
469#ifdef DDB
470					frame->tf_iir = 0;
471#endif
472				} else {
473					panic("trap: "
474					    "uvm_fault(%p, %lx, %d, %d): %d",
475					    map, va, fault, vftype, ret);
476				}
477			}
478		}
479		break;
480
481	case T_DATALIGN | T_USER:
482		sv.sival_int = va;
483		trapsignal(p, SIGBUS, vftype, BUS_ADRALN, sv);
484		break;
485
486	case T_INTERRUPT:
487	case T_INTERRUPT | T_USER:
488		cpu_intr(frame);
489		break;
490
491	case T_CONDITION:
492		panic("trap: divide by zero in the kernel");
493		break;
494
495	case T_ILLEGAL:
496	case T_ILLEGAL | T_USER:
497		/* see if it's a SPOP1,,0 */
498		if ((opcode & 0xfffffe00) == 0x10000200) {
499			frame_regmap(frame, opcode & 0x1f) = 0;
500			frame->tf_ipsw |= PSL_N;
501			break;
502		}
503		if (type & T_USER) {
504			sv.sival_int = va;
505			trapsignal(p, SIGILL, type &~ T_USER, ILL_ILLOPC, sv);
506			break;
507		}
508		/* FALLTHROUGH */
509
510	case T_LOWERPL:
511	case T_DPROT:
512	case T_IPROT:
513	case T_OVERFLOW:
514	case T_HIGHERPL:
515	case T_TAKENBR:
516	case T_POWERFAIL:
517	case T_LPMC:
518	case T_PAGEREF:
519	case T_DATAPID:
520	case T_DATAPID | T_USER:
521		if (0 /* T-chip */) {
522			break;
523		}
524		/* FALLTHROUGH to unimplemented */
525	default:
526#if 0
527if (kdb_trap (type, va, frame))
528	return;
529#endif
530		panic("trap: unimplemented \'%s\' (%d)", tts, trapnum);
531	}
532
533#ifdef DIAGNOSTIC
534	if (cpl != oldcpl)
535		printf("WARNING: SPL (%d) NOT LOWERED ON "
536		    "TRAP (%d) EXIT\n", cpl, trapnum);
537#endif
538
539	if (trapnum != T_INTERRUPT)
540		splx(cpl);	/* process softints */
541
542	/*
543	 * in case we were interrupted from the syscall gate page
544	 * treat this as we were not realy running user code no more
545	 * for weird things start to happen on return to the userland
546	 * and also see a note in locore.S:TLABEL(all)
547	 */
548	if ((type & T_USER) &&
549	    (frame->tf_iioq_head & ~PAGE_MASK) != SYSCALLGATE)
550		userret(p, frame->tf_iioq_head, 0);
551}
552
553void
554child_return(arg)
555	void *arg;
556{
557	struct proc *p = (struct proc *)arg;
558	struct trapframe *tf = p->p_md.md_regs;
559
560	/*
561	 * Set up return value registers as libc:fork() expects
562	 */
563	tf->tf_ret0 = 0;
564	tf->tf_ret1 = 1;	/* ischild */
565	tf->tf_t1 = 0;		/* errno */
566
567	userret(p, tf->tf_iioq_head, 0);
568#ifdef KTRACE
569	if (KTRPOINT(p, KTR_SYSRET))
570		ktrsysret(p, SYS_fork, 0, 0);
571#endif
572}
573
574
575/*
576 * call actual syscall routine
577 */
578void
579syscall(struct trapframe *frame)
580{
581	register struct proc *p = curproc;
582	register const struct sysent *callp;
583	int retq, nsys, code, argsize, argoff, oerror, error;
584	register_t args[8], rval[2];
585#ifdef DIAGNOSTIC
586	int oldcpl = cpl;
587#endif
588
589	uvmexp.syscalls++;
590
591	if (!USERMODE(frame->tf_iioq_head))
592		panic("syscall");
593
594	p->p_md.md_regs = frame;
595	nsys = p->p_emul->e_nsysent;
596	callp = p->p_emul->e_sysent;
597
598	argoff = 4; retq = 0;
599	switch (code = frame->tf_t1) {
600	case SYS_syscall:
601		code = frame->tf_arg0;
602		args[0] = frame->tf_arg1;
603		args[1] = frame->tf_arg2;
604		args[2] = frame->tf_arg3;
605		argoff = 3;
606		break;
607	case SYS___syscall:
608		if (callp != sysent)
609			break;
610		/*
611		 * this works, because quads get magically swapped
612		 * due to the args being laid backwards on the stack
613		 * and then copied in words
614		 */
615		code = frame->tf_arg0;
616		args[0] = frame->tf_arg2;
617		args[1] = frame->tf_arg3;
618		argoff = 2;
619		retq = 1;
620		break;
621	default:
622		args[0] = frame->tf_arg0;
623		args[1] = frame->tf_arg1;
624		args[2] = frame->tf_arg2;
625		args[3] = frame->tf_arg3;
626		break;
627	}
628
629	if (code < 0 || code >= nsys)
630		callp += p->p_emul->e_nosys;	/* bad syscall # */
631	else
632		callp += code;
633
634	oerror = error = 0;
635	if ((argsize = callp->sy_argsize)) {
636		int i;
637
638		for (i = 0, argsize -= argoff * 4;
639		    argsize > 0; i++, argsize -= 4) {
640			error = copyin((void *)(frame->tf_sp +
641			    HPPA_FRAME_ARG(i + 4)), args + i + argoff, 4);
642
643			if (error)
644				break;
645		}
646
647		/*
648		 * coming from syscall() or __syscall we must be
649		 * having one of those w/ a 64 bit arguments,
650		 * which needs a word swap due to the order
651		 * of the arguments on the stack.
652		 * this assumes that none of 'em are called
653		 * by their normal syscall number, maybe a regress
654		 * test should be used, to watch the behaviour.
655		 */
656		if (!error && argoff < 4) {
657			int t;
658
659			i = 0;
660			switch (code) {
661			case SYS_lseek:		retq = 0;
662			case SYS_truncate:
663			case SYS_ftruncate:	i = 2;	break;
664			case SYS_preadv:
665			case SYS_pwritev:
666			case SYS_pread:
667			case SYS_pwrite:	i = 4;	break;
668			case SYS_mmap:		i = 6;	break;
669			}
670
671			if (i) {
672				t = args[i];
673				args[i] = args[i + 1];
674				args[i + 1] = t;
675			}
676		}
677	}
678
679#ifdef SYSCALL_DEBUG
680	scdebug_call(p, code, args);
681#endif
682#ifdef KTRACE
683	if (KTRPOINT(p, KTR_SYSCALL))
684		ktrsyscall(p, code, callp->sy_argsize, args);
685#endif
686	if (error)
687		goto bad;
688
689	rval[0] = 0;
690	rval[1] = frame->tf_ret1;
691#if NSYSTRACE > 0
692	if (ISSET(p->p_flag, P_SYSTRACE))
693		oerror = error = systrace_redirect(code, p, args, rval);
694	else
695#endif
696		oerror = error = (*callp->sy_call)(p, args, rval);
697	p = curproc;
698	frame = p->p_md.md_regs;
699	switch (error) {
700	case 0:
701		frame->tf_ret0 = rval[0];
702		frame->tf_ret1 = rval[!retq];
703		frame->tf_t1 = 0;
704		break;
705	case ERESTART:
706		frame->tf_iioq_head -= 12;
707		frame->tf_iioq_tail -= 12;
708	case EJUSTRETURN:
709		break;
710	default:
711	bad:
712		if (p->p_emul->e_errno)
713			error = p->p_emul->e_errno[error];
714		frame->tf_t1 = error;
715		frame->tf_ret0 = error;
716		frame->tf_ret1 = 0;
717		break;
718	}
719#ifdef SYSCALL_DEBUG
720	scdebug_ret(p, code, oerror, rval);
721#endif
722	userret(p, frame->tf_iioq_head, 0);
723#ifdef KTRACE
724	if (KTRPOINT(p, KTR_SYSRET))
725		ktrsysret(p, code, oerror, rval[0]);
726#endif
727#ifdef DIAGNOSTIC
728	if (cpl != oldcpl) {
729		printf("WARNING: SPL (0x%x) NOT LOWERED ON "
730		    "syscall(0x%x, 0x%x, 0x%x, 0x%x...) EXIT, PID %d\n",
731		    cpl, code, args[0], args[1], args[2], p->p_pid);
732		cpl = oldcpl;
733	}
734#endif
735	splx(cpl);	/* process softints */
736}
737