ia32_trap.c revision 135783
1/*
2 * Copyright (c) 2004 Marcel Moolenaar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sys/ia64/ia32/ia32_trap.c 135783 2004-09-25 04:27:44Z marcel $");
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/ktr.h>
33#include <sys/sysproto.h>
34#include <sys/kernel.h>
35#include <sys/lock.h>
36#include <sys/mutex.h>
37#include <sys/pioctl.h>
38#include <sys/proc.h>
39#include <sys/signalvar.h>
40#include <sys/syscall.h>
41#include <sys/sysent.h>
42#include <machine/fpu.h>
43#include <machine/frame.h>
44#include <machine/md_var.h>
45#include <i386/include/psl.h>
46
47static void
48ia32_syscall(struct trapframe *tf)
49{
50	uint64_t args64[8];
51	uint32_t args[8];
52	struct thread *td;
53	struct proc *p;
54	struct sysent *callp;
55	caddr_t params;
56	register_t eflags;
57	u_int code;
58	int error, i, narg;
59
60	atomic_add_int(&cnt.v_syscall, 1);
61
62	td = curthread;
63	params = (caddr_t)(tf->tf_special.sp & ((1L<<32)-1)) +
64	    sizeof(uint32_t);
65	code = tf->tf_scratch.gr8;		/* eax */
66	eflags = ia64_get_eflag();
67	p = td->td_proc;
68
69	if (p->p_sysent->sv_prepsyscall == NULL) {
70		if (code == SYS_syscall) {
71			/* Code is first argument, followed by actual args. */
72			code = fuword32(params);
73			params += sizeof(int);
74		} else if (code == SYS___syscall) {
75			/*
76			 * Like syscall, but code is a quad, so as to maintain
77			 * quad alignment for the rest of the arguments.  We
78			 * use a 32-bit fetch in case params is not aligned.
79			 */
80			code = fuword32(params);
81			params += sizeof(quad_t);
82		}
83	} else
84		(*p->p_sysent->sv_prepsyscall)(tf, args, &code, &params);
85
86	if (p->p_sysent->sv_mask)
87		code &= p->p_sysent->sv_mask;
88
89	if (code >= p->p_sysent->sv_size)
90		callp = &p->p_sysent->sv_table[0];
91	else
92		callp = &p->p_sysent->sv_table[code];
93
94	narg = callp->sy_narg & SYF_ARGMASK;
95
96	/* copyin and the ktrsyscall()/ktrsysret() code is MP-aware */
97	if (params != NULL && narg != 0)
98		error = copyin(params, (caddr_t)args, narg * sizeof(int));
99	else
100		error = 0;
101
102	for (i = 0; i < narg; i++)
103		args64[i] = args[i];
104
105#ifdef KTRACE
106	if (KTRPOINT(td, KTR_SYSCALL))
107		ktrsyscall(code, narg, args64);
108#endif
109	/*
110	 * Try to run the syscall without Giant if the syscall
111	 * is MP safe.
112	 */
113	if ((callp->sy_narg & SYF_MPSAFE) == 0)
114		mtx_lock(&Giant);
115
116	if (error == 0) {
117		td->td_retval[0] = 0;
118		td->td_retval[1] = tf->tf_scratch.gr10;	/* edx */
119
120		STOPEVENT(p, S_SCE, narg);
121
122		error = (*callp->sy_call)(td, args64);
123	}
124
125	switch (error) {
126	case 0:
127		tf->tf_scratch.gr8 = td->td_retval[0];	/* eax */
128		tf->tf_scratch.gr10 = td->td_retval[1];	/* edx */
129		ia64_set_eflag(ia64_get_eflag() & ~PSL_C);
130		break;
131
132	case ERESTART:
133		/*
134		 * Reconstruct pc, assuming lcall $X,y is 7 bytes,
135		 * int 0x80 is 2 bytes. XXX Assume int 0x80.
136		 */
137		tf->tf_special.iip -= 2;
138		break;
139
140	case EJUSTRETURN:
141		break;
142
143	default:
144		if (p->p_sysent->sv_errsize) {
145			if (error >= p->p_sysent->sv_errsize)
146				error = -1;	/* XXX */
147			else
148				error = p->p_sysent->sv_errtbl[error];
149		}
150		tf->tf_scratch.gr8 = error;
151		ia64_set_eflag(ia64_get_eflag() | PSL_C);
152		break;
153	}
154
155	/*
156	 * Release Giant if we previously set it.
157	 */
158	if ((callp->sy_narg & SYF_MPSAFE) == 0)
159		mtx_unlock(&Giant);
160
161	/*
162	 * Traced syscall.
163	 */
164	if ((eflags & PSL_T) && !(eflags & PSL_VM)) {
165		ia64_set_eflag(ia64_get_eflag() & ~PSL_T);
166		trapsignal(td, SIGTRAP, 0);
167	}
168
169#ifdef KTRACE
170	if (KTRPOINT(td, KTR_SYSRET))
171		ktrsysret(code, error, td->td_retval[0]);
172#endif
173
174	/*
175	 * This works because errno is findable through the
176	 * register set.  If we ever support an emulation where this
177	 * is not the case, this code will need to be revisited.
178	 */
179	STOPEVENT(p, S_SCX, code);
180
181	WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
182	    (code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???");
183	mtx_assert(&sched_lock, MA_NOTOWNED);
184	mtx_assert(&Giant, MA_NOTOWNED);
185}
186
187/*
188 * ia32_trap() is called from exception.S to handle the IA-32 specific
189 * interruption vectors.
190 */
191void
192ia32_trap(int vector, struct trapframe *tf)
193{
194	struct proc *p;
195	struct thread *td;
196	uint64_t ucode;
197	int sig;
198	u_int sticks;
199
200	KASSERT(TRAPF_USERMODE(tf), ("%s: In kernel mode???", __func__));
201
202	ia64_set_fpsr(IA64_FPSR_DEFAULT);
203	atomic_add_int(&cnt.v_trap, 1);
204
205	td = curthread;
206	td->td_frame = tf;
207	sticks = td->td_sticks;
208	p = td->td_proc;
209	if (td->td_ucred != p->p_ucred)
210		cred_update_thread(td);
211	sig = 0;
212	ucode = 0;
213	switch (vector) {
214	case IA64_VEC_IA32_EXCEPTION:
215		switch ((tf->tf_special.isr >> 16) & 0xffff) {
216		case IA32_EXCEPTION_DIVIDE:
217			ucode = FPE_INTDIV;
218			sig = SIGFPE;
219			break;
220		case IA32_EXCEPTION_DEBUG:
221		case IA32_EXCEPTION_BREAK:
222			sig = SIGTRAP;
223			break;
224		case IA32_EXCEPTION_OVERFLOW:
225			ucode = FPE_INTOVF;
226			sig = SIGFPE;
227			break;
228		case IA32_EXCEPTION_BOUND:
229			ucode = FPE_FLTSUB;
230			sig = SIGFPE;
231			break;
232		case IA32_EXCEPTION_DNA:
233			ucode = 0;
234			sig = SIGFPE;
235			break;
236		case IA32_EXCEPTION_NOT_PRESENT:
237		case IA32_EXCEPTION_STACK_FAULT:
238		case IA32_EXCEPTION_GPFAULT:
239			ucode = (tf->tf_special.isr & 0xffff) + BUS_SEGM_FAULT;
240			sig = SIGBUS;
241			break;
242		case IA32_EXCEPTION_FPERROR:
243			ucode = 0;	/* XXX */
244			sig = SIGFPE;
245			break;
246		case IA32_EXCEPTION_ALIGNMENT_CHECK:
247			ucode = tf->tf_special.ifa;	/* VA */
248			sig = SIGBUS;
249			break;
250		case IA32_EXCEPTION_STREAMING_SIMD:
251			ucode = 0; /* XXX */
252			sig = SIGFPE;
253			break;
254		default:
255			trap_panic(vector, tf);
256			break;
257		}
258		break;
259
260	case IA64_VEC_IA32_INTERCEPT:
261		/* XXX Maybe need to emulate ia32 instruction. */
262		trap_panic(vector, tf);
263
264	case IA64_VEC_IA32_INTERRUPT:
265		/* INT n instruction - probably a syscall. */
266		if (((tf->tf_special.isr >> 16) & 0xffff) == 0x80) {
267			ia32_syscall(tf);
268			goto out;
269		}
270		ucode = (tf->tf_special.isr >> 16) & 0xffff;
271		sig = SIGILL;
272		break;
273
274	default:
275		/* Should never happen of course. */
276		trap_panic(vector, tf);
277		break;
278	}
279
280	KASSERT(sig != 0, ("%s: signal not set", __func__));
281
282	trapsignal(td, sig, ucode);
283
284out:
285	userret(td, tf, sticks);
286	mtx_assert(&Giant, MA_NOTOWNED);
287	do_ast(tf);
288}
289