aboutsummaryrefslogtreecommitdiffstats
path: root/arch/parisc/mm/fault.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/parisc/mm/fault.c')
-rw-r--r--arch/parisc/mm/fault.c58
1 files changed, 31 insertions, 27 deletions
diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c
index b2e3e9a8cece..92c7fa4ecc3f 100644
--- a/arch/parisc/mm/fault.c
+++ b/arch/parisc/mm/fault.c
@@ -139,13 +139,41 @@ parisc_acctyp(unsigned long code, unsigned int inst)
139 } 139 }
140#endif 140#endif
141 141
142int fixup_exception(struct pt_regs *regs)
143{
144 const struct exception_table_entry *fix;
145
146 fix = search_exception_tables(regs->iaoq[0]);
147 if (fix) {
148 struct exception_data *d;
149 d = &__get_cpu_var(exception_data);
150 d->fault_ip = regs->iaoq[0];
151 d->fault_space = regs->isr;
152 d->fault_addr = regs->ior;
153
154 regs->iaoq[0] = ((fix->fixup) & ~3);
155 /*
156 * NOTE: In some cases the faulting instruction
157 * may be in the delay slot of a branch. We
158 * don't want to take the branch, so we don't
159 * increment iaoq[1], instead we set it to be
160 * iaoq[0]+4, and clear the B bit in the PSW
161 */
162 regs->iaoq[1] = regs->iaoq[0] + 4;
163 regs->gr[0] &= ~PSW_B; /* IPSW in gr[0] */
164
165 return 1;
166 }
167
168 return 0;
169}
170
142void do_page_fault(struct pt_regs *regs, unsigned long code, 171void do_page_fault(struct pt_regs *regs, unsigned long code,
143 unsigned long address) 172 unsigned long address)
144{ 173{
145 struct vm_area_struct *vma, *prev_vma; 174 struct vm_area_struct *vma, *prev_vma;
146 struct task_struct *tsk = current; 175 struct task_struct *tsk = current;
147 struct mm_struct *mm = tsk->mm; 176 struct mm_struct *mm = tsk->mm;
148 const struct exception_table_entry *fix;
149 unsigned long acc_type; 177 unsigned long acc_type;
150 int fault; 178 int fault;
151 179
@@ -229,32 +257,8 @@ bad_area:
229 257
230no_context: 258no_context:
231 259
232 if (!user_mode(regs)) { 260 if (!user_mode(regs) && fixup_exception(regs)) {
233 fix = search_exception_tables(regs->iaoq[0]); 261 return;
234
235 if (fix) {
236 struct exception_data *d;
237
238 d = &__get_cpu_var(exception_data);
239 d->fault_ip = regs->iaoq[0];
240 d->fault_space = regs->isr;
241 d->fault_addr = regs->ior;
242
243 regs->iaoq[0] = ((fix->fixup) & ~3);
244
245 /*
246 * NOTE: In some cases the faulting instruction
247 * may be in the delay slot of a branch. We
248 * don't want to take the branch, so we don't
249 * increment iaoq[1], instead we set it to be
250 * iaoq[0]+4, and clear the B bit in the PSW
251 */
252
253 regs->iaoq[1] = regs->iaoq[0] + 4;
254 regs->gr[0] &= ~PSW_B; /* IPSW in gr[0] */
255
256 return;
257 }
258 } 262 }
259 263
260 parisc_terminate("Bad Address (null pointer deref?)", regs, code, address); 264 parisc_terminate("Bad Address (null pointer deref?)", regs, code, address);