|
@@ -139,13 +139,41 @@ parisc_acctyp(unsigned long code, unsigned int inst)
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
+int fixup_exception(struct pt_regs *regs)
|
|
|
|
+{
|
|
|
|
+ const struct exception_table_entry *fix;
|
|
|
|
+
|
|
|
|
+ fix = search_exception_tables(regs->iaoq[0]);
|
|
|
|
+ if (fix) {
|
|
|
|
+ struct exception_data *d;
|
|
|
|
+ d = &__get_cpu_var(exception_data);
|
|
|
|
+ d->fault_ip = regs->iaoq[0];
|
|
|
|
+ d->fault_space = regs->isr;
|
|
|
|
+ d->fault_addr = regs->ior;
|
|
|
|
+
|
|
|
|
+ regs->iaoq[0] = ((fix->fixup) & ~3);
|
|
|
|
+ /*
|
|
|
|
+ * NOTE: In some cases the faulting instruction
|
|
|
|
+ * may be in the delay slot of a branch. We
|
|
|
|
+ * don't want to take the branch, so we don't
|
|
|
|
+ * increment iaoq[1], instead we set it to be
|
|
|
|
+ * iaoq[0]+4, and clear the B bit in the PSW
|
|
|
|
+ */
|
|
|
|
+ regs->iaoq[1] = regs->iaoq[0] + 4;
|
|
|
|
+ regs->gr[0] &= ~PSW_B; /* IPSW in gr[0] */
|
|
|
|
+
|
|
|
|
+ return 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
void do_page_fault(struct pt_regs *regs, unsigned long code,
|
|
void do_page_fault(struct pt_regs *regs, unsigned long code,
|
|
unsigned long address)
|
|
unsigned long address)
|
|
{
|
|
{
|
|
struct vm_area_struct *vma, *prev_vma;
|
|
struct vm_area_struct *vma, *prev_vma;
|
|
struct task_struct *tsk = current;
|
|
struct task_struct *tsk = current;
|
|
struct mm_struct *mm = tsk->mm;
|
|
struct mm_struct *mm = tsk->mm;
|
|
- const struct exception_table_entry *fix;
|
|
|
|
unsigned long acc_type;
|
|
unsigned long acc_type;
|
|
int fault;
|
|
int fault;
|
|
|
|
|
|
@@ -229,32 +257,8 @@ bad_area:
|
|
|
|
|
|
no_context:
|
|
no_context:
|
|
|
|
|
|
- if (!user_mode(regs)) {
|
|
|
|
- fix = search_exception_tables(regs->iaoq[0]);
|
|
|
|
-
|
|
|
|
- if (fix) {
|
|
|
|
- struct exception_data *d;
|
|
|
|
-
|
|
|
|
- d = &__get_cpu_var(exception_data);
|
|
|
|
- d->fault_ip = regs->iaoq[0];
|
|
|
|
- d->fault_space = regs->isr;
|
|
|
|
- d->fault_addr = regs->ior;
|
|
|
|
-
|
|
|
|
- regs->iaoq[0] = ((fix->fixup) & ~3);
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * NOTE: In some cases the faulting instruction
|
|
|
|
- * may be in the delay slot of a branch. We
|
|
|
|
- * don't want to take the branch, so we don't
|
|
|
|
- * increment iaoq[1], instead we set it to be
|
|
|
|
- * iaoq[0]+4, and clear the B bit in the PSW
|
|
|
|
- */
|
|
|
|
-
|
|
|
|
- regs->iaoq[1] = regs->iaoq[0] + 4;
|
|
|
|
- regs->gr[0] &= ~PSW_B; /* IPSW in gr[0] */
|
|
|
|
-
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ if (!user_mode(regs) && fixup_exception(regs)) {
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
|
|
|
|
parisc_terminate("Bad Address (null pointer deref?)", regs, code, address);
|
|
parisc_terminate("Bad Address (null pointer deref?)", regs, code, address);
|