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