summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/ia64/ia64/trap.c568
1 files changed, 304 insertions, 264 deletions
diff --git a/sys/ia64/ia64/trap.c b/sys/ia64/ia64/trap.c
index e7ddb2c..a524324 100644
--- a/sys/ia64/ia64/trap.c
+++ b/sys/ia64/ia64/trap.c
@@ -311,6 +311,17 @@ printtrap(int vector, struct trapframe *framep, int isfatal, int user)
printf("\n");
}
+static void
+trap_panic(int vector, struct trapframe *tf)
+{
+
+ printtrap(vector, tf, 1, TRAPF_USERMODE(tf));
+#ifdef DDB
+ kdb_trap(vector, tf);
+#endif
+ panic("trap");
+}
+
/*
*
*/
@@ -342,18 +353,11 @@ trap(int vector, struct trapframe *framep)
struct proc *p;
struct thread *td;
u_int64_t ucode;
- int i, user;
+ int error, sig, user;
u_int sticks;
user = TRAPF_USERMODE(framep) ? 1 : 0;
- /* Short-circuit break instruction based system calls. */
- if (vector == IA64_VEC_BREAK && user &&
- framep->tf_special.ifa == 0x100000) {
- break_syscall(framep);
- return;
- }
-
/* Sanitize the FP state in case the user has trashed it. */
ia64_set_fpsr(IA64_FPSR_DEFAULT);
@@ -374,132 +378,197 @@ trap(int vector, struct trapframe *framep)
("kernel trap doesn't have ucred"));
}
+ sig = 0;
switch (vector) {
-
- case IA64_VEC_UNALIGNED_REFERENCE: {
+ case IA64_VEC_VHPT:
/*
- * If user-land, do whatever fixups, printing, and
- * signalling is appropriate (based on system-wide
- * and per-process unaligned-access-handling flags).
+ * This one is tricky. We should hardwire the VHPT, but
+ * don't at this time. I think we're mostly lucky that
+ * the VHPT is mapped.
*/
- if (user) {
- i = unaligned_fixup(framep, td);
- if (i == 0)
- goto out;
- ucode = framep->tf_special.ifa; /* VA */
- break;
- }
+ trap_panic(vector, framep);
+ break;
+
+ case IA64_VEC_ITLB:
+ case IA64_VEC_DTLB:
+ case IA64_VEC_EXT_INTR:
+ /* We never call trap() with these vectors. */
+ trap_panic(vector, framep);
+ break;
+ case IA64_VEC_ALT_ITLB:
+ case IA64_VEC_ALT_DTLB:
/*
- * Unaligned access from kernel mode is always an error,
- * EVEN IF A COPY FAULT HANDLER IS SET!
- *
- * It's an error if a copy fault handler is set because
- * the various routines which do user-initiated copies
- * do so in a bcopy-like manner. In other words, the
- * kernel never assumes that pointers provided by the
- * user are properly aligned, and so if the kernel
- * does cause an unaligned access it's a kernel bug.
+ * These should never happen, because regions 0-4 use the
+ * VHPT. If we get one of these it means we didn't program
+ * the region registers correctly.
*/
- goto dopanic;
- }
+ trap_panic(vector, framep);
+ break;
- case IA64_VEC_FLOATING_POINT_FAULT:
- /* FALLTHROUGH */
+ case IA64_VEC_NESTED_DTLB:
+ /*
+ * We never call trap() with this vector. We may want to
+ * do that in the future in case the nested TLB handler
+ * could not find the translation it needs. In that case
+ * we could switch to a special (hardwired) stack and
+ * come here to produce a nice panic().
+ */
+ trap_panic(vector, framep);
+ break;
- case IA64_VEC_FLOATING_POINT_TRAP: {
- FP_STATE fp_state;
- FPSWA_RET fpswa_ret;
- FPSWA_BUNDLE bundle;
+ case IA64_VEC_IKEY_MISS:
+ case IA64_VEC_DKEY_MISS:
+ case IA64_VEC_KEY_PERMISSION:
+ /*
+ * We don't use protection keys, so we should never get
+ * these faults.
+ */
+ trap_panic(vector, framep);
+ break;
- /* Always fatal in kernel. Should never happen. */
- if (!user)
- goto dopanic;
+ case IA64_VEC_DIRTY_BIT:
+ case IA64_VEC_INST_ACCESS:
+ case IA64_VEC_DATA_ACCESS:
+ /*
+ * We get here if we read or write to a page of which the
+ * PTE does not have the access bit or dirty bit set and
+ * we can not find the PTE in our datastructures. This
+ * either means we have a stale PTE in the TLB, or we lost
+ * the PTE in our datastructures.
+ */
+ trap_panic(vector, framep);
+ break;
- if (fpswa_interface == NULL) {
- i = SIGFPE;
- ucode = 0;
- break;
+ case IA64_VEC_BREAK:
+ if (user) {
+ if (framep->tf_special.ifa == 0x100000) {
+ break_syscall(framep);
+ return; /* do_ast() already called. */
+ } else if (framep->tf_special.ifa == 0x180000) {
+ mcontext_t mc;
+
+ error = copyin((void*)framep->tf_scratch.gr8,
+ &mc, sizeof(mc));
+ if (!error) {
+ set_mcontext(td, &mc);
+ return; /* Don't call do_ast()!!! */
+ }
+ ucode = framep->tf_scratch.gr8;
+ sig = SIGSEGV;
+ } else {
+ framep->tf_special.psr &= ~IA64_PSR_SS;
+ sig = SIGTRAP;
+ }
+ } else {
+#ifdef DDB
+ if (kdb_trap(vector, framep))
+ return;
+ panic("trap");
+#else
+ trap_panic(vector, framep);
+#endif
}
+ break;
- i = copyin((void *)(framep->tf_special.iip), &bundle, 16);
- if (i) {
- i = SIGBUS; /* EFAULT, basically */
- ucode = 0; /* exception summary */
- break;
- }
+ case IA64_VEC_PAGE_NOT_PRESENT:
+ case IA64_VEC_INST_ACCESS_RIGHTS:
+ case IA64_VEC_DATA_ACCESS_RIGHTS: {
+ vm_offset_t va;
+ struct vmspace *vm;
+ vm_map_t map;
+ vm_prot_t ftype;
+ int rv;
- /* f6-f15 are saved in exception_save */
- fp_state.bitmask_low64 = 0xffc0; /* bits 6 - 15 */
- fp_state.bitmask_high64 = 0x0;
- fp_state.fp_low_preserved = NULL;
- fp_state.fp_low_volatile = &framep->tf_scratch_fp.fr6;
- fp_state.fp_high_preserved = NULL;
- fp_state.fp_high_volatile = NULL;
+ rv = 0;
+ va = trunc_page(framep->tf_special.ifa);
- /*
- * We have the high FP registers disabled while in the
- * kernel. Enable them for the FPSWA handler only.
- */
- ia64_enable_highfp();
+ if (va >= VM_MAX_ADDRESS) {
+ /*
+ * Don't allow user-mode faults for kernel virtual
+ * addresses, including the gateway page.
+ */
+ if (user)
+ goto no_fault_in;
+ map = kernel_map;
+ } else {
+ vm = (p != NULL) ? p->p_vmspace : NULL;
+ if (vm == NULL)
+ goto no_fault_in;
+ map = &vm->vm_map;
+ }
- /* The docs are unclear. Is Fpswa reentrant? */
- fpswa_ret = fpswa_interface->Fpswa(1, &bundle,
- &framep->tf_special.psr, &framep->tf_special.fpsr,
- &framep->tf_special.isr, &framep->tf_special.pr,
- &framep->tf_special.cfm, &fp_state);
+ if (framep->tf_special.isr & IA64_ISR_X)
+ ftype = VM_PROT_EXECUTE;
+ else if (framep->tf_special.isr & IA64_ISR_W)
+ ftype = VM_PROT_WRITE;
+ else
+ ftype = VM_PROT_READ;
- ia64_disable_highfp();
+ if (map != kernel_map) {
+ /*
+ * Keep swapout from messing with us during this
+ * critical time.
+ */
+ PROC_LOCK(p);
+ ++p->p_lock;
+ PROC_UNLOCK(p);
- if (fpswa_ret.status == 0) {
- /* fixed. update ipsr and iip to next insn */
- int ei;
+ /* Fault in the user page: */
+ rv = vm_fault(map, va, ftype, (ftype & VM_PROT_WRITE)
+ ? VM_FAULT_DIRTY : VM_FAULT_NORMAL);
- ei = (framep->tf_special.isr >> 41) & 0x03;
- if (ei == 0) { /* no template for this case */
- framep->tf_special.psr &= ~IA64_ISR_EI;
- framep->tf_special.psr |= IA64_ISR_EI_1;
- } else if (ei == 1) { /* MFI or MFB */
- framep->tf_special.psr &= ~IA64_ISR_EI;
- framep->tf_special.psr |= IA64_ISR_EI_2;
- } else if (ei == 2) { /* MMF */
- framep->tf_special.psr &= ~IA64_ISR_EI;
- framep->tf_special.iip += 0x10;
- }
+ PROC_LOCK(p);
+ --p->p_lock;
+ PROC_UNLOCK(p);
+ } else {
+ /*
+ * Don't have to worry about process locking or
+ * stacks in the kernel.
+ */
+ rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
+ }
+
+ if (rv == KERN_SUCCESS)
goto out;
- } else if (fpswa_ret.status == -1) {
- printf("FATAL: FPSWA err1 %lx, err2 %lx, err3 %lx\n",
- fpswa_ret.err1, fpswa_ret.err2, fpswa_ret.err3);
- panic("fpswa fatal error on fp fault");
- } else if (fpswa_ret.status > 0) {
-#if 0
- if (fpswa_ret.status & 1) {
- /*
- * New exception needs to be raised.
- * If set then the following bits also apply:
- * & 2 -> fault was converted to a trap
- * & 4 -> SIMD caused the exception
- */
- i = SIGFPE;
- ucode = 0; /* exception summary */
- break;
+
+ no_fault_in:
+ if (!user) {
+ /* Check for copyin/copyout fault. */
+ if (td != NULL && td->td_pcb->pcb_onfault != 0) {
+ framep->tf_special.iip =
+ td->td_pcb->pcb_onfault;
+ framep->tf_special.psr &= ~IA64_PSR_RI;
+ td->td_pcb->pcb_onfault = 0;
+ goto out;
}
-#endif
- i = SIGFPE;
- ucode = 0; /* exception summary */
- break;
- } else
- panic("bad fpswa return code %lx", fpswa_ret.status);
+ trap_panic(vector, framep);
+ }
+ ucode = va;
+ sig = (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV;
+ break;
}
- case IA64_VEC_DISABLED_FP: { /* High FP registers are disabled. */
+ case IA64_VEC_GENERAL_EXCEPTION:
+ case IA64_VEC_NAT_CONSUMPTION:
+ case IA64_VEC_SPECULATION:
+ case IA64_VEC_UNSUPP_DATA_REFERENCE:
+ case IA64_VEC_LOWER_PRIVILEGE_TRANSFER:
+ if (user) {
+ ucode = vector;
+ sig = SIGILL;
+ } else
+ trap_panic(vector, framep);
+ break;
+
+ case IA64_VEC_DISABLED_FP: {
struct pcpu *pcpu;
struct pcb *pcb;
struct thread *thr;
/* Always fatal in kernel. Should never happen. */
if (!user)
- goto dopanic;
+ trap_panic(vector, framep);
pcb = td->td_pcb;
pcpu = pcb->pcb_fpcpu;
@@ -577,220 +646,198 @@ trap(int vector, struct trapframe *framep)
ia64_highfp_load(td);
framep->tf_special.psr &= ~IA64_PSR_DFH;
goto out;
- break;
}
- case IA64_VEC_PAGE_NOT_PRESENT:
- case IA64_VEC_INST_ACCESS_RIGHTS:
- case IA64_VEC_DATA_ACCESS_RIGHTS: {
- vm_offset_t va;
- struct vmspace *vm;
- vm_map_t map;
- vm_prot_t ftype;
- int rv;
-
- rv = 0;
- va = trunc_page(framep->tf_special.ifa);
-
- if (va >= VM_MAX_ADDRESS) {
- /*
- * Don't allow user-mode faults for kernel virtual
- * addresses, including the gateway page.
- */
- if (user)
- goto no_fault_in;
- map = kernel_map;
- } else {
- vm = (p != NULL) ? p->p_vmspace : NULL;
- if (vm == NULL)
- goto no_fault_in;
- map = &vm->vm_map;
- }
-
- if (framep->tf_special.isr & IA64_ISR_X)
- ftype = VM_PROT_EXECUTE;
- else if (framep->tf_special.isr & IA64_ISR_W)
- ftype = VM_PROT_WRITE;
- else
- ftype = VM_PROT_READ;
-
- if (map != kernel_map) {
- /*
- * Keep swapout from messing with us during this
- * critical time.
- */
- PROC_LOCK(p);
- ++p->p_lock;
- PROC_UNLOCK(p);
-
- /* Fault in the user page: */
- rv = vm_fault(map, va, ftype, (ftype & VM_PROT_WRITE)
- ? VM_FAULT_DIRTY : VM_FAULT_NORMAL);
-
- PROC_LOCK(p);
- --p->p_lock;
- PROC_UNLOCK(p);
- } else {
- /*
- * Don't have to worry about process locking or
- * stacks in the kernel.
- */
- rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
- }
-
- if (rv == KERN_SUCCESS)
- goto out;
-
- no_fault_in:
- if (!user) {
- /* Check for copyin/copyout fault. */
- if (td != NULL && td->td_pcb->pcb_onfault != 0) {
- framep->tf_special.iip =
- td->td_pcb->pcb_onfault;
- framep->tf_special.psr &= ~IA64_PSR_RI;
- td->td_pcb->pcb_onfault = 0;
- goto out;
- }
- goto dopanic;
- }
- ucode = va;
- i = (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV;
- break;
- }
-
- case IA64_VEC_BREAK:
case IA64_VEC_DEBUG:
+ case IA64_VEC_TAKEN_BRANCH_TRAP:
case IA64_VEC_SINGLE_STEP_TRAP:
- case IA64_VEC_TAKEN_BRANCH_TRAP: {
framep->tf_special.psr &= ~IA64_PSR_SS;
-
- /*
- * These are always fatal in kernel, and should never happen.
- */
if (!user) {
#ifdef DDB
- /*
- * ...unless, of course, DDB is configured.
- */
if (kdb_trap(vector, framep))
return;
-
- /*
- * If we get here, DDB did _not_ handle the
- * trap, and we need to PANIC!
- */
+ panic("trap");
+#else
+ trap_panic(vector, framep);
#endif
- goto dopanic;
}
- i = SIGTRAP;
+ sig = SIGTRAP;
break;
- }
- case IA64_VEC_GENERAL_EXCEPTION: {
+ case IA64_VEC_UNALIGNED_REFERENCE:
+ /*
+ * If user-land, do whatever fixups, printing, and
+ * signalling is appropriate (based on system-wide
+ * and per-process unaligned-access-handling flags).
+ */
if (user) {
- ucode = vector;
- i = SIGILL;
+ sig = unaligned_fixup(framep, td);
+ if (sig == 0)
+ goto out;
+ ucode = framep->tf_special.ifa; /* VA */
+ } else
+ trap_panic(vector, framep);
+ break;
+
+ case IA64_VEC_FLOATING_POINT_FAULT:
+ case IA64_VEC_FLOATING_POINT_TRAP: {
+ FP_STATE fp_state;
+ FPSWA_RET fpswa_ret;
+ FPSWA_BUNDLE bundle;
+
+ /* Always fatal in kernel. Should never happen. */
+ if (!user)
+ trap_panic(vector, framep);
+
+ if (fpswa_interface == NULL) {
+ sig = SIGFPE;
+ ucode = 0;
break;
}
- goto dopanic;
- }
- case IA64_VEC_UNSUPP_DATA_REFERENCE:
- case IA64_VEC_LOWER_PRIVILEGE_TRANSFER: {
- if (user) {
- ucode = vector;
- i = SIGBUS;
+ error = copyin((void *)(framep->tf_special.iip), &bundle, 16);
+ if (error) {
+ sig = SIGBUS; /* EFAULT, basically */
+ ucode = 0; /* exception summary */
break;
}
- goto dopanic;
- }
- case IA64_VEC_IA32_EXCEPTION: {
- u_int64_t isr = framep->tf_special.isr;
+ /* f6-f15 are saved in exception_save */
+ fp_state.bitmask_low64 = 0xffc0; /* bits 6 - 15 */
+ fp_state.bitmask_high64 = 0x0;
+ fp_state.fp_low_preserved = NULL;
+ fp_state.fp_low_volatile = &framep->tf_scratch_fp.fr6;
+ fp_state.fp_high_preserved = NULL;
+ fp_state.fp_high_volatile = NULL;
+
+ /*
+ * We have the high FP registers disabled while in the
+ * kernel. Enable them for the FPSWA handler only.
+ */
+ ia64_enable_highfp();
+
+ /* The docs are unclear. Is Fpswa reentrant? */
+ fpswa_ret = fpswa_interface->Fpswa(1, &bundle,
+ &framep->tf_special.psr, &framep->tf_special.fpsr,
+ &framep->tf_special.isr, &framep->tf_special.pr,
+ &framep->tf_special.cfm, &fp_state);
+
+ ia64_disable_highfp();
+
+ if (fpswa_ret.status == 0) {
+ /* fixed. update ipsr and iip to next insn */
+ int ei;
- switch ((isr >> 16) & 0xffff) {
+ ei = (framep->tf_special.isr >> 41) & 0x03;
+ if (ei == 0) { /* no template for this case */
+ framep->tf_special.psr &= ~IA64_ISR_EI;
+ framep->tf_special.psr |= IA64_ISR_EI_1;
+ } else if (ei == 1) { /* MFI or MFB */
+ framep->tf_special.psr &= ~IA64_ISR_EI;
+ framep->tf_special.psr |= IA64_ISR_EI_2;
+ } else if (ei == 2) { /* MMF */
+ framep->tf_special.psr &= ~IA64_ISR_EI;
+ framep->tf_special.iip += 0x10;
+ }
+ goto out;
+ } else if (fpswa_ret.status == -1) {
+ printf("FATAL: FPSWA err1 %lx, err2 %lx, err3 %lx\n",
+ fpswa_ret.err1, fpswa_ret.err2, fpswa_ret.err3);
+ panic("fpswa fatal error on fp fault");
+ } else if (fpswa_ret.status > 0) {
+#if 0
+ if (fpswa_ret.status & 1) {
+ /*
+ * New exception needs to be raised.
+ * If set then the following bits also apply:
+ * & 2 -> fault was converted to a trap
+ * & 4 -> SIMD caused the exception
+ */
+ sig = SIGFPE;
+ ucode = 0; /* exception summary */
+ break;
+ }
+#endif
+ sig = SIGFPE;
+ ucode = 0; /* exception summary */
+ break;
+ } else
+ panic("bad fpswa return code %lx", fpswa_ret.status);
+ }
+
+ case IA64_VEC_IA32_EXCEPTION:
+ switch ((framep->tf_special.isr >> 16) & 0xffff) {
case IA32_EXCEPTION_DIVIDE:
ucode = FPE_INTDIV;
- i = SIGFPE;
+ sig = SIGFPE;
break;
-
case IA32_EXCEPTION_DEBUG:
case IA32_EXCEPTION_BREAK:
- i = SIGTRAP;
+ sig = SIGTRAP;
break;
-
case IA32_EXCEPTION_OVERFLOW:
ucode = FPE_INTOVF;
- i = SIGFPE;
+ sig = SIGFPE;
break;
-
case IA32_EXCEPTION_BOUND:
ucode = FPE_FLTSUB;
- i = SIGFPE;
+ sig = SIGFPE;
break;
-
case IA32_EXCEPTION_DNA:
ucode = 0;
- i = SIGFPE;
+ sig = SIGFPE;
break;
-
case IA32_EXCEPTION_NOT_PRESENT:
case IA32_EXCEPTION_STACK_FAULT:
case IA32_EXCEPTION_GPFAULT:
- ucode = (isr & 0xffff) + BUS_SEGM_FAULT;
- i = SIGBUS;
+ ucode = (framep->tf_special.isr & 0xffff) +
+ BUS_SEGM_FAULT;
+ sig = SIGBUS;
break;
-
case IA32_EXCEPTION_FPERROR:
- ucode = 0; /* XXX */
- i = SIGFPE;
+ ucode = 0; /* XXX */
+ sig = SIGFPE;
break;
-
case IA32_EXCEPTION_ALIGNMENT_CHECK:
ucode = framep->tf_special.ifa; /* VA */
- i = SIGBUS;
+ sig = SIGBUS;
break;
-
case IA32_EXCEPTION_STREAMING_SIMD:
ucode = 0; /* XXX */
- i = SIGFPE;
+ sig = SIGFPE;
break;
-
default:
- goto dopanic;
+ trap_panic(vector, framep);
+ break;
}
break;
- }
- case IA64_VEC_IA32_INTERRUPT: {
- /*
- * INT n instruction - probably a syscall.
- */
+ case IA64_VEC_IA32_INTERCEPT:
+ /* XXX Maybe need to emulate ia32 instruction. */
+ trap_panic(vector, framep);
+
+ case IA64_VEC_IA32_INTERRUPT:
+ /* INT n instruction - probably a syscall. */
if (((framep->tf_special.isr >> 16) & 0xffff) == 0x80) {
ia32_syscall(framep);
goto out;
- } else {
- ucode = (framep->tf_special.isr >> 16) & 0xffff;
- i = SIGILL;
- break;
}
- }
-
- case IA64_VEC_IA32_INTERCEPT: {
- /*
- * Maybe need to emulate ia32 instruction.
- */
- goto dopanic;
- }
+ ucode = (framep->tf_special.isr >> 16) & 0xffff;
+ sig = SIGILL;
+ break;
default:
- goto dopanic;
+ /* Reserved vectors get here. Should never happen of course. */
+ trap_panic(vector, framep);
+ break;
}
+ KASSERT(sig != 0, ("foo"));
+
if (print_usertrap)
printtrap(vector, framep, 1, user);
- trapsignal(td, i, ucode);
+ trapsignal(td, sig, ucode);
out:
if (user) {
@@ -802,13 +849,6 @@ out:
do_ast(framep);
}
return;
-
-dopanic:
- printtrap(vector, framep, 1, user);
-#ifdef DDB
- kdb_trap(vector, framep);
-#endif
- panic("trap");
}
OpenPOWER on IntegriCloud