summaryrefslogtreecommitdiffstats
path: root/sys/ia64/ia32/ia32_trap.c
diff options
context:
space:
mode:
authormarcel <marcel@FreeBSD.org>2004-09-25 04:27:44 +0000
committermarcel <marcel@FreeBSD.org>2004-09-25 04:27:44 +0000
commit883da4df6b30c6a6a1889e38615386b37af594de (patch)
tree8de6820f7af882f731e1d689d5d242fb96cc1bc7 /sys/ia64/ia32/ia32_trap.c
parent954ae57b986db4b14140e76aebb189c88e5634d8 (diff)
downloadFreeBSD-src-883da4df6b30c6a6a1889e38615386b37af594de.zip
FreeBSD-src-883da4df6b30c6a6a1889e38615386b37af594de.tar.gz
Move the IA-32 trap handling from trap() to ia32_trap(). Move the
ia32_syscall() function along with it to ia32_trap.c. When COMPAT_IA32 is not defined, we'll raise SIGEMT instead.
Diffstat (limited to 'sys/ia64/ia32/ia32_trap.c')
-rw-r--r--sys/ia64/ia32/ia32_trap.c288
1 files changed, 288 insertions, 0 deletions
diff --git a/sys/ia64/ia32/ia32_trap.c b/sys/ia64/ia32/ia32_trap.c
new file mode 100644
index 0000000..cbc6c09
--- /dev/null
+++ b/sys/ia64/ia32/ia32_trap.c
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2004 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/ktr.h>
+#include <sys/sysproto.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/pioctl.h>
+#include <sys/proc.h>
+#include <sys/signalvar.h>
+#include <sys/syscall.h>
+#include <sys/sysent.h>
+#include <machine/fpu.h>
+#include <machine/frame.h>
+#include <machine/md_var.h>
+#include <i386/include/psl.h>
+
+static void
+ia32_syscall(struct trapframe *tf)
+{
+ uint64_t args64[8];
+ uint32_t args[8];
+ struct thread *td;
+ struct proc *p;
+ struct sysent *callp;
+ caddr_t params;
+ register_t eflags;
+ u_int code;
+ int error, i, narg;
+
+ atomic_add_int(&cnt.v_syscall, 1);
+
+ td = curthread;
+ params = (caddr_t)(tf->tf_special.sp & ((1L<<32)-1)) +
+ sizeof(uint32_t);
+ code = tf->tf_scratch.gr8; /* eax */
+ eflags = ia64_get_eflag();
+ p = td->td_proc;
+
+ if (p->p_sysent->sv_prepsyscall == NULL) {
+ if (code == SYS_syscall) {
+ /* Code is first argument, followed by actual args. */
+ code = fuword32(params);
+ params += sizeof(int);
+ } else if (code == SYS___syscall) {
+ /*
+ * Like syscall, but code is a quad, so as to maintain
+ * quad alignment for the rest of the arguments. We
+ * use a 32-bit fetch in case params is not aligned.
+ */
+ code = fuword32(params);
+ params += sizeof(quad_t);
+ }
+ } else
+ (*p->p_sysent->sv_prepsyscall)(tf, args, &code, &params);
+
+ if (p->p_sysent->sv_mask)
+ code &= p->p_sysent->sv_mask;
+
+ if (code >= p->p_sysent->sv_size)
+ callp = &p->p_sysent->sv_table[0];
+ else
+ callp = &p->p_sysent->sv_table[code];
+
+ narg = callp->sy_narg & SYF_ARGMASK;
+
+ /* copyin and the ktrsyscall()/ktrsysret() code is MP-aware */
+ if (params != NULL && narg != 0)
+ error = copyin(params, (caddr_t)args, narg * sizeof(int));
+ else
+ error = 0;
+
+ for (i = 0; i < narg; i++)
+ args64[i] = args[i];
+
+#ifdef KTRACE
+ if (KTRPOINT(td, KTR_SYSCALL))
+ ktrsyscall(code, narg, args64);
+#endif
+ /*
+ * Try to run the syscall without Giant if the syscall
+ * is MP safe.
+ */
+ if ((callp->sy_narg & SYF_MPSAFE) == 0)
+ mtx_lock(&Giant);
+
+ if (error == 0) {
+ td->td_retval[0] = 0;
+ td->td_retval[1] = tf->tf_scratch.gr10; /* edx */
+
+ STOPEVENT(p, S_SCE, narg);
+
+ error = (*callp->sy_call)(td, args64);
+ }
+
+ switch (error) {
+ case 0:
+ tf->tf_scratch.gr8 = td->td_retval[0]; /* eax */
+ tf->tf_scratch.gr10 = td->td_retval[1]; /* edx */
+ ia64_set_eflag(ia64_get_eflag() & ~PSL_C);
+ break;
+
+ case ERESTART:
+ /*
+ * Reconstruct pc, assuming lcall $X,y is 7 bytes,
+ * int 0x80 is 2 bytes. XXX Assume int 0x80.
+ */
+ tf->tf_special.iip -= 2;
+ break;
+
+ case EJUSTRETURN:
+ break;
+
+ default:
+ if (p->p_sysent->sv_errsize) {
+ if (error >= p->p_sysent->sv_errsize)
+ error = -1; /* XXX */
+ else
+ error = p->p_sysent->sv_errtbl[error];
+ }
+ tf->tf_scratch.gr8 = error;
+ ia64_set_eflag(ia64_get_eflag() | PSL_C);
+ break;
+ }
+
+ /*
+ * Release Giant if we previously set it.
+ */
+ if ((callp->sy_narg & SYF_MPSAFE) == 0)
+ mtx_unlock(&Giant);
+
+ /*
+ * Traced syscall.
+ */
+ if ((eflags & PSL_T) && !(eflags & PSL_VM)) {
+ ia64_set_eflag(ia64_get_eflag() & ~PSL_T);
+ trapsignal(td, SIGTRAP, 0);
+ }
+
+#ifdef KTRACE
+ if (KTRPOINT(td, KTR_SYSRET))
+ ktrsysret(code, error, td->td_retval[0]);
+#endif
+
+ /*
+ * This works because errno is findable through the
+ * register set. If we ever support an emulation where this
+ * is not the case, this code will need to be revisited.
+ */
+ STOPEVENT(p, S_SCX, code);
+
+ WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
+ (code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???");
+ mtx_assert(&sched_lock, MA_NOTOWNED);
+ mtx_assert(&Giant, MA_NOTOWNED);
+}
+
+/*
+ * ia32_trap() is called from exception.S to handle the IA-32 specific
+ * interruption vectors.
+ */
+void
+ia32_trap(int vector, struct trapframe *tf)
+{
+ struct proc *p;
+ struct thread *td;
+ uint64_t ucode;
+ int sig;
+ u_int sticks;
+
+ KASSERT(TRAPF_USERMODE(tf), ("%s: In kernel mode???", __func__));
+
+ ia64_set_fpsr(IA64_FPSR_DEFAULT);
+ atomic_add_int(&cnt.v_trap, 1);
+
+ td = curthread;
+ td->td_frame = tf;
+ sticks = td->td_sticks;
+ p = td->td_proc;
+ if (td->td_ucred != p->p_ucred)
+ cred_update_thread(td);
+ sig = 0;
+ ucode = 0;
+ switch (vector) {
+ case IA64_VEC_IA32_EXCEPTION:
+ switch ((tf->tf_special.isr >> 16) & 0xffff) {
+ case IA32_EXCEPTION_DIVIDE:
+ ucode = FPE_INTDIV;
+ sig = SIGFPE;
+ break;
+ case IA32_EXCEPTION_DEBUG:
+ case IA32_EXCEPTION_BREAK:
+ sig = SIGTRAP;
+ break;
+ case IA32_EXCEPTION_OVERFLOW:
+ ucode = FPE_INTOVF;
+ sig = SIGFPE;
+ break;
+ case IA32_EXCEPTION_BOUND:
+ ucode = FPE_FLTSUB;
+ sig = SIGFPE;
+ break;
+ case IA32_EXCEPTION_DNA:
+ ucode = 0;
+ sig = SIGFPE;
+ break;
+ case IA32_EXCEPTION_NOT_PRESENT:
+ case IA32_EXCEPTION_STACK_FAULT:
+ case IA32_EXCEPTION_GPFAULT:
+ ucode = (tf->tf_special.isr & 0xffff) + BUS_SEGM_FAULT;
+ sig = SIGBUS;
+ break;
+ case IA32_EXCEPTION_FPERROR:
+ ucode = 0; /* XXX */
+ sig = SIGFPE;
+ break;
+ case IA32_EXCEPTION_ALIGNMENT_CHECK:
+ ucode = tf->tf_special.ifa; /* VA */
+ sig = SIGBUS;
+ break;
+ case IA32_EXCEPTION_STREAMING_SIMD:
+ ucode = 0; /* XXX */
+ sig = SIGFPE;
+ break;
+ default:
+ trap_panic(vector, tf);
+ break;
+ }
+ break;
+
+ case IA64_VEC_IA32_INTERCEPT:
+ /* XXX Maybe need to emulate ia32 instruction. */
+ trap_panic(vector, tf);
+
+ case IA64_VEC_IA32_INTERRUPT:
+ /* INT n instruction - probably a syscall. */
+ if (((tf->tf_special.isr >> 16) & 0xffff) == 0x80) {
+ ia32_syscall(tf);
+ goto out;
+ }
+ ucode = (tf->tf_special.isr >> 16) & 0xffff;
+ sig = SIGILL;
+ break;
+
+ default:
+ /* Should never happen of course. */
+ trap_panic(vector, tf);
+ break;
+ }
+
+ KASSERT(sig != 0, ("%s: signal not set", __func__));
+
+ trapsignal(td, sig, ucode);
+
+out:
+ userret(td, tf, sticks);
+ mtx_assert(&Giant, MA_NOTOWNED);
+ do_ast(tf);
+}
OpenPOWER on IntegriCloud