ia32_trap.c revision 151316
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 151316 2005-10-14 12:43:47Z davidxu $");
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/cpu.h>
43#include <machine/fpu.h>
44#include <machine/frame.h>
45#include <machine/md_var.h>
46#include <i386/include/psl.h>
47
48#ifdef WITNESS
49extern char *syscallnames[];
50#endif
51
52static void
53ia32_syscall(struct trapframe *tf)
54{
55	uint64_t args64[8];
56	uint32_t args[8];
57	struct thread *td;
58	struct proc *p;
59	struct sysent *callp;
60	caddr_t params;
61	register_t eflags;
62	u_int code;
63	int error, i, narg;
64	ksiginfo_t ksi;
65
66	PCPU_LAZY_INC(cnt.v_syscall);
67
68	td = curthread;
69	params = (caddr_t)(tf->tf_special.sp & ((1L<<32)-1)) +
70	    sizeof(uint32_t);
71	code = tf->tf_scratch.gr8;		/* eax */
72	eflags = ia64_get_eflag();
73	p = td->td_proc;
74
75	if (p->p_sysent->sv_prepsyscall == NULL) {
76		if (code == SYS_syscall) {
77			/* Code is first argument, followed by actual args. */
78			code = fuword32(params);
79			params += sizeof(int);
80		} else if (code == SYS___syscall) {
81			/*
82			 * Like syscall, but code is a quad, so as to maintain
83			 * quad alignment for the rest of the arguments.  We
84			 * use a 32-bit fetch in case params is not aligned.
85			 */
86			code = fuword32(params);
87			params += sizeof(quad_t);
88		}
89	} else
90		(*p->p_sysent->sv_prepsyscall)(tf, args, &code, &params);
91
92	if (p->p_sysent->sv_mask)
93		code &= p->p_sysent->sv_mask;
94
95	if (code >= p->p_sysent->sv_size)
96		callp = &p->p_sysent->sv_table[0];
97	else
98		callp = &p->p_sysent->sv_table[code];
99
100	narg = callp->sy_narg & SYF_ARGMASK;
101
102	/* copyin and the ktrsyscall()/ktrsysret() code is MP-aware */
103	if (params != NULL && narg != 0)
104		error = copyin(params, (caddr_t)args, narg * sizeof(int));
105	else
106		error = 0;
107
108	for (i = 0; i < narg; i++)
109		args64[i] = args[i];
110
111#ifdef KTRACE
112	if (KTRPOINT(td, KTR_SYSCALL))
113		ktrsyscall(code, narg, args64);
114#endif
115	/*
116	 * Try to run the syscall without Giant if the syscall
117	 * is MP safe.
118	 */
119	if ((callp->sy_narg & SYF_MPSAFE) == 0)
120		mtx_lock(&Giant);
121
122	if (error == 0) {
123		td->td_retval[0] = 0;
124		td->td_retval[1] = tf->tf_scratch.gr10;	/* edx */
125
126		STOPEVENT(p, S_SCE, narg);
127
128		error = (*callp->sy_call)(td, args64);
129	}
130
131	switch (error) {
132	case 0:
133		tf->tf_scratch.gr8 = td->td_retval[0];	/* eax */
134		tf->tf_scratch.gr10 = td->td_retval[1];	/* edx */
135		ia64_set_eflag(ia64_get_eflag() & ~PSL_C);
136		break;
137
138	case ERESTART:
139		/*
140		 * Reconstruct pc, assuming lcall $X,y is 7 bytes,
141		 * int 0x80 is 2 bytes. XXX Assume int 0x80.
142		 */
143		tf->tf_special.iip -= 2;
144		break;
145
146	case EJUSTRETURN:
147		break;
148
149	default:
150		if (p->p_sysent->sv_errsize) {
151			if (error >= p->p_sysent->sv_errsize)
152				error = -1;	/* XXX */
153			else
154				error = p->p_sysent->sv_errtbl[error];
155		}
156		tf->tf_scratch.gr8 = error;
157		ia64_set_eflag(ia64_get_eflag() | PSL_C);
158		break;
159	}
160
161	/*
162	 * Release Giant if we previously set it.
163	 */
164	if ((callp->sy_narg & SYF_MPSAFE) == 0)
165		mtx_unlock(&Giant);
166
167	/*
168	 * Traced syscall.
169	 */
170	if ((eflags & PSL_T) && !(eflags & PSL_VM)) {
171		ia64_set_eflag(ia64_get_eflag() & ~PSL_T);
172		ksiginfo_init_trap(&ksi);
173		ksi.ksi_signo = SIGTRAP;
174		ksi.ksi_code = TRAP_TRACE;
175		ksi.ksi_addr = (void *)tf->tf_special.iip;
176		trapsignal(td, &ksi);
177	}
178
179#ifdef KTRACE
180	if (KTRPOINT(td, KTR_SYSRET))
181		ktrsysret(code, error, td->td_retval[0]);
182#endif
183
184	/*
185	 * This works because errno is findable through the
186	 * register set.  If we ever support an emulation where this
187	 * is not the case, this code will need to be revisited.
188	 */
189	STOPEVENT(p, S_SCX, code);
190
191	WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
192	    (code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???");
193	mtx_assert(&sched_lock, MA_NOTOWNED);
194	mtx_assert(&Giant, MA_NOTOWNED);
195}
196
197/*
198 * ia32_trap() is called from exception.S to handle the IA-32 specific
199 * interruption vectors.
200 */
201void
202ia32_trap(int vector, struct trapframe *tf)
203{
204	struct proc *p;
205	struct thread *td;
206	uint64_t ucode;
207	int sig;
208	u_int sticks;
209	ksiginfo_t ksi;
210
211	KASSERT(TRAPF_USERMODE(tf), ("%s: In kernel mode???", __func__));
212
213	ia64_set_fpsr(IA64_FPSR_DEFAULT);
214	PCPU_LAZY_INC(cnt.v_trap);
215
216	td = curthread;
217	td->td_frame = tf;
218	sticks = td->td_sticks;
219	p = td->td_proc;
220	if (td->td_ucred != p->p_ucred)
221		cred_update_thread(td);
222	sig = 0;
223	ucode = 0;
224	switch (vector) {
225	case IA64_VEC_IA32_EXCEPTION:
226		switch ((tf->tf_special.isr >> 16) & 0xffff) {
227		case IA32_EXCEPTION_DIVIDE:
228			ucode = FPE_INTDIV;
229			sig = SIGFPE;
230			break;
231		case IA32_EXCEPTION_DEBUG:
232		case IA32_EXCEPTION_BREAK:
233			sig = SIGTRAP;
234			break;
235		case IA32_EXCEPTION_OVERFLOW:
236			ucode = FPE_INTOVF;
237			sig = SIGFPE;
238			break;
239		case IA32_EXCEPTION_BOUND:
240			ucode = FPE_FLTSUB;
241			sig = SIGFPE;
242			break;
243		case IA32_EXCEPTION_DNA:
244			ucode = 0;
245			sig = SIGFPE;
246			break;
247		case IA32_EXCEPTION_NOT_PRESENT:
248		case IA32_EXCEPTION_STACK_FAULT:
249		case IA32_EXCEPTION_GPFAULT:
250			ucode = (tf->tf_special.isr & 0xffff) + BUS_SEGM_FAULT;
251			sig = SIGBUS;
252			break;
253		case IA32_EXCEPTION_FPERROR:
254			ucode = 0;	/* XXX */
255			sig = SIGFPE;
256			break;
257		case IA32_EXCEPTION_ALIGNMENT_CHECK:
258			ucode = tf->tf_special.ifa;	/* VA */
259			sig = SIGBUS;
260			break;
261		case IA32_EXCEPTION_STREAMING_SIMD:
262			ucode = 0; /* XXX */
263			sig = SIGFPE;
264			break;
265		default:
266			trap_panic(vector, tf);
267			break;
268		}
269		break;
270
271	case IA64_VEC_IA32_INTERCEPT:
272		/* XXX Maybe need to emulate ia32 instruction. */
273		trap_panic(vector, tf);
274
275	case IA64_VEC_IA32_INTERRUPT:
276		/* INT n instruction - probably a syscall. */
277		if (((tf->tf_special.isr >> 16) & 0xffff) == 0x80) {
278			ia32_syscall(tf);
279			goto out;
280		}
281		ucode = (tf->tf_special.isr >> 16) & 0xffff;
282		sig = SIGILL;
283		break;
284
285	default:
286		/* Should never happen of course. */
287		trap_panic(vector, tf);
288		break;
289	}
290
291	KASSERT(sig != 0, ("%s: signal not set", __func__));
292
293	ksiginfo_init_trap(&ksi);
294	ksi.ksi_signo = sig;
295	ksi.ksi_code = (int)ucode; /* XXX */
296	/* ksi.ksi_addr */
297	trapsignal(td, &ksi);
298
299out:
300	userret(td, tf, sticks);
301	mtx_assert(&Giant, MA_NOTOWNED);
302	do_ast(tf);
303}
304