ia32_trap.c revision 160770
1193323Sed/*-
2193323Sed * Copyright (c) 2004 Marcel Moolenaar
3193323Sed * All rights reserved.
4193323Sed *
5193323Sed * Redistribution and use in source and binary forms, with or without
6193323Sed * modification, are permitted provided that the following conditions
7193323Sed * are met:
8193323Sed *
9193323Sed * 1. Redistributions of source code must retain the above copyright
10193323Sed *    notice, this list of conditions and the following disclaimer.
11193323Sed * 2. Redistributions in binary form must reproduce the above copyright
12193323Sed *    notice, this list of conditions and the following disclaimer in the
13193323Sed *    documentation and/or other materials provided with the distribution.
14193323Sed *
15193323Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16198090Srdivacky * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17193323Sed * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18198892Srdivacky * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19198090Srdivacky * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20193323Sed * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21198090Srdivacky * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22193323Sed * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23193323Sed * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24198892Srdivacky * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25193323Sed */
26193323Sed
27193323Sed#include <sys/cdefs.h>
28193323Sed__FBSDID("$FreeBSD: head/sys/ia64/ia32/ia32_trap.c 160770 2006-07-27 21:25:50Z jhb $");
29193323Sed
30193323Sed#include <sys/param.h>
31198090Srdivacky#include <sys/systm.h>
32198090Srdivacky#include <sys/ktr.h>
33198090Srdivacky#include <sys/sysproto.h>
34193323Sed#include <sys/kernel.h>
35193323Sed#include <sys/lock.h>
36198892Srdivacky#include <sys/mutex.h>
37198892Srdivacky#include <sys/pioctl.h>
38198892Srdivacky#include <sys/proc.h>
39198892Srdivacky#include <sys/ptrace.h>
40198892Srdivacky#include <sys/signalvar.h>
41198892Srdivacky#include <sys/syscall.h>
42198892Srdivacky#include <sys/sysent.h>
43198892Srdivacky#include <machine/cpu.h>
44198892Srdivacky#include <machine/fpu.h>
45198892Srdivacky#include <machine/frame.h>
46198892Srdivacky#include <machine/md_var.h>
47198892Srdivacky#include <i386/include/psl.h>
48198892Srdivacky
49198892Srdivacky#ifdef WITNESS
50198892Srdivackyextern char *syscallnames[];
51198892Srdivacky#endif
52198892Srdivacky
53198892Srdivackystatic void
54198892Srdivackyia32_syscall(struct trapframe *tf)
55198892Srdivacky{
56198892Srdivacky	uint64_t args64[8];
57198892Srdivacky	uint32_t args[8];
58198892Srdivacky	struct thread *td;
59198892Srdivacky	struct proc *p;
60193323Sed	struct sysent *callp;
61198892Srdivacky	caddr_t params;
62198892Srdivacky	register_t eflags;
63198892Srdivacky	u_int code;
64198892Srdivacky	int error, i, narg;
65198892Srdivacky	ksiginfo_t ksi;
66198892Srdivacky
67198892Srdivacky	PCPU_LAZY_INC(cnt.v_syscall);
68198892Srdivacky
69198892Srdivacky	td = curthread;
70198892Srdivacky	params = (caddr_t)(tf->tf_special.sp & ((1L<<32)-1)) +
71198892Srdivacky	    sizeof(uint32_t);
72198892Srdivacky	code = tf->tf_scratch.gr8;		/* eax */
73198892Srdivacky	eflags = ia64_get_eflag();
74198892Srdivacky	p = td->td_proc;
75198892Srdivacky
76198892Srdivacky	if (p->p_sysent->sv_prepsyscall == NULL) {
77198892Srdivacky		if (code == SYS_syscall) {
78198892Srdivacky			/* Code is first argument, followed by actual args. */
79198892Srdivacky			code = fuword32(params);
80198892Srdivacky			params += sizeof(int);
81193323Sed		} else if (code == SYS___syscall) {
82198892Srdivacky			/*
83198892Srdivacky			 * Like syscall, but code is a quad, so as to maintain
84198892Srdivacky			 * quad alignment for the rest of the arguments.  We
85198892Srdivacky			 * use a 32-bit fetch in case params is not aligned.
86198892Srdivacky			 */
87198892Srdivacky			code = fuword32(params);
88198892Srdivacky			params += sizeof(quad_t);
89198892Srdivacky		}
90198892Srdivacky	} else
91198892Srdivacky		(*p->p_sysent->sv_prepsyscall)(tf, args, &code, &params);
92198892Srdivacky
93198892Srdivacky	if (p->p_sysent->sv_mask)
94198892Srdivacky		code &= p->p_sysent->sv_mask;
95198892Srdivacky
96198892Srdivacky	if (code >= p->p_sysent->sv_size)
97198892Srdivacky		callp = &p->p_sysent->sv_table[0];
98198892Srdivacky	else
99198892Srdivacky		callp = &p->p_sysent->sv_table[code];
100198892Srdivacky
101198892Srdivacky	narg = callp->sy_narg & SYF_ARGMASK;
102198892Srdivacky
103198892Srdivacky	/* copyin and the ktrsyscall()/ktrsysret() code is MP-aware */
104198892Srdivacky	if (params != NULL && narg != 0)
105198892Srdivacky		error = copyin(params, (caddr_t)args, narg * sizeof(int));
106198892Srdivacky	else
107198892Srdivacky		error = 0;
108198892Srdivacky
109193323Sed	for (i = 0; i < narg; i++)
110193323Sed		args64[i] = args[i];
111198892Srdivacky
112193323Sed#ifdef KTRACE
113198892Srdivacky	if (KTRPOINT(td, KTR_SYSCALL))
114198892Srdivacky		ktrsyscall(code, narg, args64);
115198892Srdivacky#endif
116198892Srdivacky	CTR4(KTR_SYSC, "syscall enter thread %p pid %d proc %s code %d", td,
117198892Srdivacky	    td->td_proc->p_pid, td->td_proc->p_comm, code);
118198892Srdivacky
119198892Srdivacky	/*
120198892Srdivacky	 * Try to run the syscall without Giant if the syscall
121193323Sed	 * is MP safe.
122193323Sed	 */
123193323Sed	if ((callp->sy_narg & SYF_MPSAFE) == 0)
124193323Sed		mtx_lock(&Giant);
125193323Sed
126193323Sed	if (error == 0) {
127193323Sed		td->td_retval[0] = 0;
128193323Sed		td->td_retval[1] = tf->tf_scratch.gr10;	/* edx */
129198892Srdivacky
130193323Sed		STOPEVENT(p, S_SCE, narg);
131193323Sed
132193323Sed		PTRACESTOP_SC(p, td, S_PT_SCE);
133193323Sed
134		error = (*callp->sy_call)(td, args64);
135	}
136
137	switch (error) {
138	case 0:
139		tf->tf_scratch.gr8 = td->td_retval[0];	/* eax */
140		tf->tf_scratch.gr10 = td->td_retval[1];	/* edx */
141		ia64_set_eflag(ia64_get_eflag() & ~PSL_C);
142		break;
143
144	case ERESTART:
145		/*
146		 * Reconstruct pc, assuming lcall $X,y is 7 bytes,
147		 * int 0x80 is 2 bytes. XXX Assume int 0x80.
148		 */
149		tf->tf_special.iip -= 2;
150		break;
151
152	case EJUSTRETURN:
153		break;
154
155	default:
156		if (p->p_sysent->sv_errsize) {
157			if (error >= p->p_sysent->sv_errsize)
158				error = -1;	/* XXX */
159			else
160				error = p->p_sysent->sv_errtbl[error];
161		}
162		tf->tf_scratch.gr8 = error;
163		ia64_set_eflag(ia64_get_eflag() | PSL_C);
164		break;
165	}
166
167	/*
168	 * Release Giant if we previously set it.
169	 */
170	if ((callp->sy_narg & SYF_MPSAFE) == 0)
171		mtx_unlock(&Giant);
172
173	/*
174	 * Traced syscall.
175	 */
176	if ((eflags & PSL_T) && !(eflags & PSL_VM)) {
177		ia64_set_eflag(ia64_get_eflag() & ~PSL_T);
178		ksiginfo_init_trap(&ksi);
179		ksi.ksi_signo = SIGTRAP;
180		ksi.ksi_code = TRAP_TRACE;
181		ksi.ksi_addr = (void *)tf->tf_special.iip;
182		trapsignal(td, &ksi);
183	}
184
185	/*
186	 * End of syscall tracing.
187	 */
188	CTR4(KTR_SYSC, "syscall exit thread %p pid %d proc %s code %d", td,
189	    td->td_proc->p_pid, td->td_proc->p_comm, code);
190#ifdef KTRACE
191	if (KTRPOINT(td, KTR_SYSRET))
192		ktrsysret(code, error, td->td_retval[0]);
193#endif
194
195	/*
196	 * This works because errno is findable through the
197	 * register set.  If we ever support an emulation where this
198	 * is not the case, this code will need to be revisited.
199	 */
200	STOPEVENT(p, S_SCX, code);
201
202	PTRACESTOP_SC(p, td, S_PT_SCX);
203
204	WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
205	    (code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???");
206	mtx_assert(&sched_lock, MA_NOTOWNED);
207	mtx_assert(&Giant, MA_NOTOWNED);
208}
209
210/*
211 * ia32_trap() is called from exception.S to handle the IA-32 specific
212 * interruption vectors.
213 */
214void
215ia32_trap(int vector, struct trapframe *tf)
216{
217	struct proc *p;
218	struct thread *td;
219	uint64_t ucode;
220	int sig;
221	ksiginfo_t ksi;
222
223	KASSERT(TRAPF_USERMODE(tf), ("%s: In kernel mode???", __func__));
224
225	ia64_set_fpsr(IA64_FPSR_DEFAULT);
226	PCPU_LAZY_INC(cnt.v_trap);
227
228	td = curthread;
229	td->td_frame = tf;
230	td->td_pticks = 0;
231	p = td->td_proc;
232	if (td->td_ucred != p->p_ucred)
233		cred_update_thread(td);
234	sig = 0;
235	ucode = 0;
236	switch (vector) {
237	case IA64_VEC_IA32_EXCEPTION:
238		switch ((tf->tf_special.isr >> 16) & 0xffff) {
239		case IA32_EXCEPTION_DIVIDE:
240			ucode = FPE_INTDIV;
241			sig = SIGFPE;
242			break;
243		case IA32_EXCEPTION_DEBUG:
244		case IA32_EXCEPTION_BREAK:
245			sig = SIGTRAP;
246			break;
247		case IA32_EXCEPTION_OVERFLOW:
248			ucode = FPE_INTOVF;
249			sig = SIGFPE;
250			break;
251		case IA32_EXCEPTION_BOUND:
252			ucode = FPE_FLTSUB;
253			sig = SIGFPE;
254			break;
255		case IA32_EXCEPTION_DNA:
256			ucode = 0;
257			sig = SIGFPE;
258			break;
259		case IA32_EXCEPTION_NOT_PRESENT:
260		case IA32_EXCEPTION_STACK_FAULT:
261		case IA32_EXCEPTION_GPFAULT:
262			ucode = (tf->tf_special.isr & 0xffff) + BUS_SEGM_FAULT;
263			sig = SIGBUS;
264			break;
265		case IA32_EXCEPTION_FPERROR:
266			ucode = 0;	/* XXX */
267			sig = SIGFPE;
268			break;
269		case IA32_EXCEPTION_ALIGNMENT_CHECK:
270			ucode = tf->tf_special.ifa;	/* VA */
271			sig = SIGBUS;
272			break;
273		case IA32_EXCEPTION_STREAMING_SIMD:
274			ucode = 0; /* XXX */
275			sig = SIGFPE;
276			break;
277		default:
278			trap_panic(vector, tf);
279			break;
280		}
281		break;
282
283	case IA64_VEC_IA32_INTERCEPT:
284		/* XXX Maybe need to emulate ia32 instruction. */
285		trap_panic(vector, tf);
286
287	case IA64_VEC_IA32_INTERRUPT:
288		/* INT n instruction - probably a syscall. */
289		if (((tf->tf_special.isr >> 16) & 0xffff) == 0x80) {
290			ia32_syscall(tf);
291			goto out;
292		}
293		ucode = (tf->tf_special.isr >> 16) & 0xffff;
294		sig = SIGILL;
295		break;
296
297	default:
298		/* Should never happen of course. */
299		trap_panic(vector, tf);
300		break;
301	}
302
303	KASSERT(sig != 0, ("%s: signal not set", __func__));
304
305	ksiginfo_init_trap(&ksi);
306	ksi.ksi_signo = sig;
307	ksi.ksi_code = (int)ucode; /* XXX */
308	/* ksi.ksi_addr */
309	trapsignal(td, &ksi);
310
311out:
312	userret(td, tf);
313	mtx_assert(&Giant, MA_NOTOWNED);
314	do_ast(tf);
315}
316