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