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, ¶ms); 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